@lovable.dev/mcp-js 0.22.1 → 0.22.2-rc.1
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-CumVyk7p.d.cts +27 -0
- package/dist/authorize-D6p4-9_D.d.ts +27 -0
- package/dist/base-DCe0kP79.d.cts +29 -0
- package/dist/base-DCe0kP79.d.ts +29 -0
- package/dist/cli/extract-manifest.cjs +116 -201
- package/dist/cli/extract-manifest.d.cts +1 -1
- package/dist/cli/extract-manifest.d.ts +1 -1
- package/dist/cli/extract-manifest.js +117 -156
- package/dist/content-D5LJAHyM.js +12 -0
- package/dist/content-NCYIGgOb.cjs +17 -0
- package/dist/context-BweeEcoA.cjs +56 -0
- package/dist/context-CIpPzN7P.js +51 -0
- package/dist/cors-C2n2LxrC.js +830 -0
- package/dist/cors-Cga2PWEg.cjs +913 -0
- package/dist/forwarded--h4efJy-.js +43 -0
- package/dist/forwarded-Pi8Hs5Ps.cjs +48 -0
- package/dist/fs-errors-CWNzOV75.cjs +11 -0
- package/dist/fs-errors-PA2t1TIp.js +6 -0
- package/dist/index.cjs +129 -329
- package/dist/index.d.cts +26 -26
- package/dist/index.d.ts +26 -26
- package/dist/index.js +118 -177
- package/dist/{io-D4srzRKc.d.ts → io-CfSPxeBN.d.ts} +6 -4
- package/dist/io-DPYvBqET.d.cts +15 -0
- package/dist/list-tools-07OV14rK.cjs +57 -0
- package/dist/list-tools-B4TTPEl1.d.cts +8 -0
- package/dist/list-tools-I8Hvub9P.js +46 -0
- package/dist/list-tools-bh6-eqZM.d.ts +8 -0
- package/dist/logger-2OXtfiIW.js +141 -0
- package/dist/logger-BqPOa_E1.cjs +194 -0
- package/dist/mcp-B6z5Givq.js +123 -0
- package/dist/mcp-DLv_c1O5.cjs +128 -0
- package/dist/metadata-path-CAkNcfyY.js +12 -0
- package/dist/metadata-path-zd7NSNoa.cjs +17 -0
- package/dist/package-CxQcGWdU.cjs +9 -0
- package/dist/package-xS6mk-b_.js +4 -0
- package/dist/paths-IS65L6TA.js +7 -0
- package/dist/paths-OP318a6c.cjs +18 -0
- package/dist/protocols/mcp/index.cjs +3 -750
- package/dist/protocols/mcp/index.d.cts +6 -7
- package/dist/protocols/mcp/index.d.ts +6 -7
- package/dist/protocols/mcp/index.js +2 -12
- package/dist/protocols/oauth-metadata.cjs +48 -539
- package/dist/protocols/oauth-metadata.d.cts +5 -6
- package/dist/protocols/oauth-metadata.d.ts +5 -6
- package/dist/protocols/oauth-metadata.js +52 -10
- package/dist/protocols/rest/index.cjs +5 -843
- package/dist/protocols/rest/index.d.cts +7 -10
- package/dist/protocols/rest/index.d.ts +7 -10
- package/dist/protocols/rest/index.js +3 -16
- package/dist/rest-CggWx00c.js +117 -0
- package/dist/rest-DxhK7-3b.cjs +122 -0
- package/dist/stacks/supabase/index.cjs +76 -1318
- package/dist/stacks/supabase/index.d.cts +29 -30
- package/dist/stacks/supabase/index.d.ts +29 -30
- package/dist/stacks/supabase/index.js +73 -89
- package/dist/stacks/supabase/vite.cjs +258 -287
- 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 +42 -1272
- package/dist/stacks/tanstack/index.d.cts +8 -9
- package/dist/stacks/tanstack/index.d.ts +8 -9
- package/dist/stacks/tanstack/index.js +36 -41
- package/dist/stacks/tanstack/vite.cjs +223 -312
- package/dist/stacks/tanstack/vite.d.cts +80 -81
- package/dist/stacks/tanstack/vite.d.ts +80 -81
- package/dist/stacks/tanstack/vite.js +216 -282
- package/dist/types-BYdYYTjk.d.cts +321 -0
- package/dist/types-BYdYYTjk.d.ts +321 -0
- package/package.json +4 -4
- package/dist/authorize-BMeXd_Sh.d.ts +0 -25
- package/dist/base-CM-KCpp6.d.ts +0 -28
- package/dist/chunk-5HVSJCKE.js +0 -114
- package/dist/chunk-6DXGZZA4.js +0 -6
- package/dist/chunk-6QFZYYUV.js +0 -11
- package/dist/chunk-6SZOFKGH.js +0 -58
- package/dist/chunk-H37EB22A.js +0 -125
- package/dist/chunk-IFDWUM7L.js +0 -741
- package/dist/chunk-IXZIFYO6.js +0 -79
- package/dist/chunk-MA5H6PSF.js +0 -46
- package/dist/chunk-TJN33K5U.js +0 -141
- package/dist/chunk-UQK5UO6C.js +0 -26
- package/dist/chunk-XQWJN6DC.js +0 -14
- package/dist/chunk-Y3ZFPEQH.js +0 -8
- package/dist/chunk-ZQXSWTPU.js +0 -6
- package/dist/types-qqrmJ736.d.ts +0 -321
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { t as McpPluginApi } from "../../io-CfSPxeBN.js";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
//#region src/stacks/supabase/vite.d.ts
|
|
4
4
|
interface McpPluginOptions {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Path to the MCP entry file (default export = `defineMcp(...)` result),
|
|
7
|
+
* relative to the project root.
|
|
8
|
+
* @default "src/lib/mcp/index.ts"
|
|
9
|
+
*/
|
|
10
|
+
mcpEntry?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Directory holding Supabase function folders (one per function), relative
|
|
13
|
+
* to the project root.
|
|
14
|
+
* @default "supabase/functions"
|
|
15
|
+
*/
|
|
16
|
+
functionsDir?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Name of the function directory under `functionsDir`. Becomes the public
|
|
19
|
+
* URL segment (`/functions/v1/<functionName>`) the dispatcher binds OAuth
|
|
20
|
+
* metadata to via `resourcePath`.
|
|
21
|
+
* @default "mcp"
|
|
22
|
+
*/
|
|
23
|
+
functionName?: string;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Vite plugin that emits the Supabase Edge Function entry (and its
|
|
@@ -46,5 +46,5 @@ interface McpPluginOptions {
|
|
|
46
46
|
* cleans up SDK-owned files when the entry is deleted.
|
|
47
47
|
*/
|
|
48
48
|
declare function mcpPlugin(options?: McpPluginOptions): Plugin;
|
|
49
|
-
|
|
50
|
-
export { type McpPluginOptions, mcpPlugin as default, mcpPlugin };
|
|
49
|
+
//#endregion
|
|
50
|
+
export { type McpPluginApi, McpPluginOptions, mcpPlugin as default, mcpPlugin };
|
|
@@ -1,284 +1,284 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "../../
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
assertFunctionName
|
|
7
|
-
} from "../../chunk-XQWJN6DC.js";
|
|
8
|
-
import {
|
|
9
|
-
version
|
|
10
|
-
} from "../../chunk-ZQXSWTPU.js";
|
|
11
|
-
|
|
12
|
-
// src/stacks/supabase/vite.ts
|
|
13
|
-
import { resolve as resolve2, sep as sep2 } from "path";
|
|
1
|
+
import { t as version } from "../../package-xS6mk-b_.js";
|
|
2
|
+
import { t as isFileMissing } from "../../fs-errors-PA2t1TIp.js";
|
|
3
|
+
import { n as assertFunctionName, t as FUNCTIONS_MOUNT_PREFIX } from "../../paths-IS65L6TA.js";
|
|
4
|
+
import { lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
14
6
|
import { loadEnv } from "vite";
|
|
15
|
-
|
|
16
|
-
// src/stacks/supabase/emit.ts
|
|
17
7
|
import { build } from "esbuild";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
var DEFAULT_MCP_ENTRY = "src/lib/mcp/index.ts";
|
|
21
|
-
var DEFAULT_FUNCTIONS_DIR = "supabase/functions";
|
|
22
|
-
var DEFAULT_FUNCTION_NAME = "mcp";
|
|
23
|
-
var GENERATED_BANNER = "// AUTO-GENERATED by @lovable.dev/mcp-js \u2014 do not edit. Regenerated by the Vite plugin.\n// To take ownership, delete this banner line; the plugin then leaves the file alone.";
|
|
24
|
-
var GENERATED_JSON_MARKER_KEY = "_lovableMcpGenerated";
|
|
8
|
+
const GENERATED_BANNER = "// AUTO-GENERATED by @lovable.dev/mcp-js — do not edit. Regenerated by the Vite plugin.\n// To take ownership, delete this banner line; the plugin then leaves the file alone.";
|
|
9
|
+
const GENERATED_JSON_MARKER_KEY = "_lovableMcpGenerated";
|
|
25
10
|
function fileExists(path) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
11
|
+
try {
|
|
12
|
+
lstatSync(path);
|
|
13
|
+
return true;
|
|
14
|
+
} catch (err) {
|
|
15
|
+
if (isFileMissing(err)) return false;
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
34
18
|
}
|
|
35
19
|
function hasGeneratedBanner(content) {
|
|
36
|
-
|
|
20
|
+
return content.replace(/\r\n/g, "\n").startsWith(GENERATED_BANNER);
|
|
37
21
|
}
|
|
38
22
|
function hasGeneratedJsonMarker(content) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(content);
|
|
25
|
+
return typeof parsed === "object" && parsed !== null && GENERATED_JSON_MARKER_KEY in parsed;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
45
29
|
}
|
|
46
30
|
function writeIfChanged(file, content, ownershipCheck) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (existing === content)
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
64
|
-
writeFileSync(file, content, "utf8");
|
|
65
|
-
return true;
|
|
31
|
+
let existing;
|
|
32
|
+
try {
|
|
33
|
+
existing = readFileSync(file, "utf8");
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (!isFileMissing(err)) throw err;
|
|
36
|
+
}
|
|
37
|
+
if (existing !== void 0) {
|
|
38
|
+
if (!ownershipCheck(existing)) throw new Error(`@lovable.dev/mcp-js: refusing to overwrite user-authored file at ${file}. Delete it or move it first.`);
|
|
39
|
+
if (existing === content) return false;
|
|
40
|
+
}
|
|
41
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
42
|
+
writeFileSync(file, content, "utf8");
|
|
43
|
+
return true;
|
|
66
44
|
}
|
|
67
45
|
function readProjectDependencyVersions(projectRoot) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
46
|
+
try {
|
|
47
|
+
const pkg = JSON.parse(readFileSync(join(projectRoot, "package.json"), "utf8"));
|
|
48
|
+
return {
|
|
49
|
+
...pkg.peerDependencies,
|
|
50
|
+
...pkg.devDependencies,
|
|
51
|
+
...pkg.dependencies
|
|
52
|
+
};
|
|
53
|
+
} catch {
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
74
56
|
}
|
|
75
57
|
function npmSpecifierFor(bare, versions) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return version2 ? `npm:${pkg}@${version2}${subpath}` : `npm:${pkg}${subpath}`;
|
|
58
|
+
const pkg = bare.startsWith("@") ? bare.split("/").slice(0, 2).join("/") : bare.split("/")[0];
|
|
59
|
+
const subpath = bare.slice(pkg.length);
|
|
60
|
+
if (pkg === "@lovable.dev/mcp-js") return `npm:${pkg}@${version}${subpath}`;
|
|
61
|
+
const range = versions[pkg];
|
|
62
|
+
const version$1 = range && /^[\dv^~>=]|^latest$/.test(range) ? range : void 0;
|
|
63
|
+
return version$1 ? `npm:${pkg}@${version$1}${subpath}` : `npm:${pkg}${subpath}`;
|
|
83
64
|
}
|
|
84
65
|
function externalizeBareAsNpm(versions) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
66
|
+
return {
|
|
67
|
+
name: "lovable-mcp-externalize-bare-as-npm",
|
|
68
|
+
setup(pluginBuild) {
|
|
69
|
+
pluginBuild.onResolve({ filter: /.*/ }, (args) => {
|
|
70
|
+
const p = args.path;
|
|
71
|
+
if (p.startsWith(".") || p.startsWith("/")) return null;
|
|
72
|
+
if (/^(npm|node|jsr|https?|data):/.test(p)) return {
|
|
73
|
+
path: p,
|
|
74
|
+
external: true
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
path: npmSpecifierFor(p, versions),
|
|
78
|
+
external: true
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
98
83
|
}
|
|
99
84
|
function importMetaEnvDefines(inlineEnv) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
defines[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
105
|
-
}
|
|
106
|
-
return defines;
|
|
85
|
+
const env = inlineEnv ?? {};
|
|
86
|
+
const defines = { "import.meta.env": JSON.stringify(env) };
|
|
87
|
+
for (const [key, value] of Object.entries(env)) if (/^[A-Za-z_$][\w$]*$/.test(key)) defines[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
88
|
+
return defines;
|
|
107
89
|
}
|
|
108
90
|
async function bundleFunctionEntry(projectRoot, mcpEntryAbs, functionName, inlineEnv) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// Bundled from ${relative(projectRoot, mcpEntryAbs).split(sep).join("/")} by @lovable.dev/mcp-js
|
|
132
|
-
|
|
133
|
-
|
|
91
|
+
const versions = readProjectDependencyVersions(projectRoot);
|
|
92
|
+
const result = await build({
|
|
93
|
+
stdin: {
|
|
94
|
+
contents: `import mcp from ${JSON.stringify(mcpEntryAbs)};\nimport { createSupabaseHandler } from "@lovable.dev/mcp-js/stacks/supabase";\nDeno.serve(createSupabaseHandler(mcp, { functionName: ${JSON.stringify(functionName)} }));\n`,
|
|
95
|
+
resolveDir: projectRoot,
|
|
96
|
+
sourcefile: "lovable-mcp-supabase-entry.ts",
|
|
97
|
+
loader: "ts"
|
|
98
|
+
},
|
|
99
|
+
bundle: true,
|
|
100
|
+
write: false,
|
|
101
|
+
metafile: true,
|
|
102
|
+
format: "esm",
|
|
103
|
+
platform: "neutral",
|
|
104
|
+
target: "esnext",
|
|
105
|
+
absWorkingDir: projectRoot,
|
|
106
|
+
logLevel: "silent",
|
|
107
|
+
define: importMetaEnvDefines(inlineEnv),
|
|
108
|
+
plugins: [externalizeBareAsNpm(versions)]
|
|
109
|
+
});
|
|
110
|
+
const out = result.outputFiles[0]?.text ?? "";
|
|
111
|
+
const inputs = Object.keys(result.metafile?.inputs ?? {}).filter((p) => !p.startsWith("<") && !p.startsWith("npm:")).map((p) => resolve(projectRoot, p));
|
|
112
|
+
return {
|
|
113
|
+
code: `${GENERATED_BANNER}\n// supabase function: ${functionName}\n// Bundled from ${relative(projectRoot, mcpEntryAbs).split(sep).join("/")} by @lovable.dev/mcp-js.\n` + out,
|
|
114
|
+
inputs
|
|
115
|
+
};
|
|
134
116
|
}
|
|
135
117
|
function resolvePaths(options) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
functionDir,
|
|
149
|
-
functionEntry: join(functionDir, "index.ts"),
|
|
150
|
-
mcpEntryAbs: resolve(projectRoot, mcpEntry)
|
|
151
|
-
};
|
|
118
|
+
const projectRoot = resolve(options.projectRoot);
|
|
119
|
+
const mcpEntry = options.mcpEntry ?? "src/lib/mcp/index.ts";
|
|
120
|
+
const functionsDir = options.functionsDir ?? "supabase/functions";
|
|
121
|
+
const functionName = options.functionName ?? "mcp";
|
|
122
|
+
assertFunctionName(functionName);
|
|
123
|
+
const functionDir = resolve(projectRoot, functionsDir, functionName);
|
|
124
|
+
if (functionDir !== projectRoot && !functionDir.startsWith(projectRoot + sep)) throw new Error(`@lovable.dev/mcp-js: functionsDir must resolve within the project root, got ${JSON.stringify(functionsDir)}`);
|
|
125
|
+
return {
|
|
126
|
+
functionDir,
|
|
127
|
+
functionEntry: join(functionDir, "index.ts"),
|
|
128
|
+
mcpEntryAbs: resolve(projectRoot, mcpEntry)
|
|
129
|
+
};
|
|
152
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Sync the Supabase function for an MCP entry. Bundles the entry (and its local
|
|
133
|
+
* import graph) into a self-contained `supabase/functions/<name>/index.ts` with
|
|
134
|
+
* direct `npm:` specifiers, and removes the SDK-owned files when the entry
|
|
135
|
+
* disappears so deleting it leaves no stale boilerplate behind. No `deno.json`
|
|
136
|
+
* is emitted — the bundle carries no bare imports, so an import map is moot, and
|
|
137
|
+
* a legacy generated `deno.json` is cleaned up below.
|
|
138
|
+
*/
|
|
153
139
|
async function syncSupabaseFunction(options) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
140
|
+
const projectRoot = resolve(options.projectRoot);
|
|
141
|
+
const paths = resolvePaths(options);
|
|
142
|
+
const functionName = options.functionName ?? "mcp";
|
|
143
|
+
const written = [];
|
|
144
|
+
const removed = [];
|
|
145
|
+
if (!fileExists(paths.mcpEntryAbs)) {
|
|
146
|
+
cleanupOrphans(paths.functionDir, /* @__PURE__ */ new Set(), removed);
|
|
147
|
+
return {
|
|
148
|
+
written,
|
|
149
|
+
removed,
|
|
150
|
+
inputs: []
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const { code, inputs } = await bundleFunctionEntry(projectRoot, paths.mcpEntryAbs, functionName, options.inlineEnv);
|
|
154
|
+
if (writeIfChanged(paths.functionEntry, code, hasGeneratedBanner)) written.push(paths.functionEntry);
|
|
155
|
+
cleanupOrphans(paths.functionDir, /* @__PURE__ */ new Set([paths.functionEntry]), removed);
|
|
156
|
+
return {
|
|
157
|
+
written,
|
|
158
|
+
removed,
|
|
159
|
+
inputs
|
|
160
|
+
};
|
|
169
161
|
}
|
|
170
162
|
function cleanupOrphans(functionDir, expected, removed) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
} catch (err) {
|
|
196
|
-
if (!isFileMissing(err))
|
|
197
|
-
throw err;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
163
|
+
let entries;
|
|
164
|
+
try {
|
|
165
|
+
entries = readdirSync(functionDir);
|
|
166
|
+
} catch (err) {
|
|
167
|
+
if (isFileMissing(err)) return;
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
const full = join(functionDir, entry);
|
|
172
|
+
if (expected.has(full)) continue;
|
|
173
|
+
let content;
|
|
174
|
+
try {
|
|
175
|
+
content = readFileSync(full, "utf8");
|
|
176
|
+
} catch (err) {
|
|
177
|
+
if (isFileMissing(err) || err.code === "EISDIR") continue;
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
180
|
+
if (hasGeneratedBanner(content) || hasGeneratedJsonMarker(content)) try {
|
|
181
|
+
unlinkSync(full);
|
|
182
|
+
removed.push(full);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
if (!isFileMissing(err)) throw err;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
201
187
|
}
|
|
202
|
-
|
|
203
|
-
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/stacks/supabase/vite.ts
|
|
204
190
|
function normalizePath(p) {
|
|
205
|
-
|
|
191
|
+
return p.split(sep).join("/");
|
|
206
192
|
}
|
|
207
193
|
function productionImportMetaEnv(config) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
194
|
+
return {
|
|
195
|
+
...loadEnv("production", config.envDir, config.envPrefix),
|
|
196
|
+
MODE: "production",
|
|
197
|
+
BASE_URL: config.base ?? "/",
|
|
198
|
+
DEV: false,
|
|
199
|
+
PROD: true,
|
|
200
|
+
SSR: false
|
|
201
|
+
};
|
|
216
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Vite plugin that emits the Supabase Edge Function entry (and its
|
|
205
|
+
* `deno.json` import map) for an `@lovable.dev/mcp-js` MCP server.
|
|
206
|
+
*
|
|
207
|
+
* Place this in your `vite.config.ts` plugins array. It uses Vite as the
|
|
208
|
+
* trigger for codegen even though the emitted output (Deno function) is
|
|
209
|
+
* not part of the Vite bundle — Classic Lovable stacks already run Vite
|
|
210
|
+
* for the frontend, so it's the natural authoring surface.
|
|
211
|
+
*
|
|
212
|
+
* Lifecycle, mirroring `stacks/tanstack/vite`:
|
|
213
|
+
* - `configResolved` finalizes the project root and runs the first emit.
|
|
214
|
+
* - `buildStart` re-runs the emit so a `vite build` always picks up the
|
|
215
|
+
* latest source.
|
|
216
|
+
* - `configureServer` re-emits when the entry or any bundled source file
|
|
217
|
+
* (tools, local helpers) changes during `vite dev`, so editing a tool
|
|
218
|
+
* regenerates the function without restarting the server.
|
|
219
|
+
*
|
|
220
|
+
* The entry and its local import graph are bundled by esbuild into one
|
|
221
|
+
* self-contained Deno module (deps left as `npm:` specifiers), so the deployed
|
|
222
|
+
* function carries no cross-project imports the Supabase deploy can't upload.
|
|
223
|
+
* Idempotent: `syncSupabaseFunction` writes only on byte-level change and
|
|
224
|
+
* cleans up SDK-owned files when the entry is deleted.
|
|
225
|
+
*/
|
|
217
226
|
function mcpPlugin(options = {}) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
});
|
|
274
|
-
},
|
|
275
|
-
async buildStart() {
|
|
276
|
-
await regenerate();
|
|
277
|
-
}
|
|
278
|
-
};
|
|
227
|
+
const mcpEntryOption = options.mcpEntry ?? "src/lib/mcp/index.ts";
|
|
228
|
+
const functionsDirOption = options.functionsDir ?? "supabase/functions";
|
|
229
|
+
const functionName = options.functionName ?? "mcp";
|
|
230
|
+
const urlPath = `${FUNCTIONS_MOUNT_PREFIX}${functionName}`;
|
|
231
|
+
let projectRoot = process.cwd();
|
|
232
|
+
let mcpEntryAbs = resolve(projectRoot, mcpEntryOption);
|
|
233
|
+
let inlineEnv = {};
|
|
234
|
+
let watchedInputs = /* @__PURE__ */ new Set();
|
|
235
|
+
const regenerate = async () => {
|
|
236
|
+
const { inputs } = await syncSupabaseFunction({
|
|
237
|
+
projectRoot,
|
|
238
|
+
mcpEntry: mcpEntryOption,
|
|
239
|
+
functionsDir: functionsDirOption,
|
|
240
|
+
functionName,
|
|
241
|
+
inlineEnv
|
|
242
|
+
});
|
|
243
|
+
watchedInputs = new Set(inputs.map(normalizePath));
|
|
244
|
+
};
|
|
245
|
+
return {
|
|
246
|
+
name: "@lovable.dev/mcp-js/supabase",
|
|
247
|
+
api: {
|
|
248
|
+
get mcpEntry() {
|
|
249
|
+
return mcpEntryAbs;
|
|
250
|
+
},
|
|
251
|
+
urlPath
|
|
252
|
+
},
|
|
253
|
+
async configResolved(config) {
|
|
254
|
+
projectRoot = config.root;
|
|
255
|
+
mcpEntryAbs = resolve(projectRoot, mcpEntryOption);
|
|
256
|
+
inlineEnv = productionImportMetaEnv(config);
|
|
257
|
+
await regenerate();
|
|
258
|
+
},
|
|
259
|
+
configureServer(server) {
|
|
260
|
+
const onChange = (file) => {
|
|
261
|
+
const norm = normalizePath(file);
|
|
262
|
+
if (norm !== normalizePath(mcpEntryAbs) && !watchedInputs.has(norm)) return;
|
|
263
|
+
regenerate().catch((err) => {
|
|
264
|
+
const message = `[@lovable.dev/mcp-js] failed to regenerate the Supabase function: ${err instanceof Error ? err.message : String(err)}`;
|
|
265
|
+
if (server.config?.logger?.error) server.config.logger.error(message);
|
|
266
|
+
else console.error(message);
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
server.watcher.on("add", onChange);
|
|
270
|
+
server.watcher.on("change", onChange);
|
|
271
|
+
server.watcher.on("unlink", onChange);
|
|
272
|
+
server.watcher.once("close", () => {
|
|
273
|
+
server.watcher.off("add", onChange);
|
|
274
|
+
server.watcher.off("change", onChange);
|
|
275
|
+
server.watcher.off("unlink", onChange);
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
async buildStart() {
|
|
279
|
+
await regenerate();
|
|
280
|
+
}
|
|
281
|
+
};
|
|
279
282
|
}
|
|
280
|
-
|
|
281
|
-
export {
|
|
282
|
-
vite_default as default,
|
|
283
|
-
mcpPlugin
|
|
284
|
-
};
|
|
283
|
+
//#endregion
|
|
284
|
+
export { mcpPlugin as default, mcpPlugin };
|