devlens-mcp 0.4.2 → 0.5.2
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/README.md +211 -35
- package/RELEASE_NOTES.md +3 -7
- package/dist/bin/cli.js +41 -14
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/setup.d.ts +14 -0
- package/dist/bin/setup.d.ts.map +1 -0
- package/dist/bin/setup.js +272 -0
- package/dist/bin/setup.js.map +1 -0
- package/dist/src/figma/figma-api.d.ts +108 -0
- package/dist/src/figma/figma-api.d.ts.map +1 -0
- package/dist/src/figma/figma-api.js +284 -0
- package/dist/src/figma/figma-api.js.map +1 -0
- package/dist/src/figma/figma-cache.d.ts +57 -0
- package/dist/src/figma/figma-cache.d.ts.map +1 -0
- package/dist/src/figma/figma-cache.js +266 -0
- package/dist/src/figma/figma-cache.js.map +1 -0
- package/dist/src/figma/figma-client.d.ts +62 -0
- package/dist/src/figma/figma-client.d.ts.map +1 -0
- package/dist/src/figma/figma-client.js +224 -0
- package/dist/src/figma/figma-client.js.map +1 -0
- package/dist/src/figma/figma-rate-limiter.d.ts +46 -0
- package/dist/src/figma/figma-rate-limiter.d.ts.map +1 -0
- package/dist/src/figma/figma-rate-limiter.js +153 -0
- package/dist/src/figma/figma-rate-limiter.js.map +1 -0
- package/dist/src/figma/figma-retry.d.ts +19 -0
- package/dist/src/figma/figma-retry.d.ts.map +1 -0
- package/dist/src/figma/figma-retry.js +57 -0
- package/dist/src/figma/figma-retry.js.map +1 -0
- package/dist/src/figma/figma-structure.d.ts +1 -1
- package/dist/src/figma/figma-structure.d.ts.map +1 -1
- package/dist/src/figma/figma-structure.js +11 -1
- package/dist/src/figma/figma-structure.js.map +1 -1
- package/dist/src/figma/figma-types.d.ts +54 -0
- package/dist/src/figma/figma-types.d.ts.map +1 -0
- package/dist/src/figma/figma-types.js +33 -0
- package/dist/src/figma/figma-types.js.map +1 -0
- package/dist/src/figma/url-parser.d.ts +40 -0
- package/dist/src/figma/url-parser.d.ts.map +1 -0
- package/dist/src/figma/url-parser.js +107 -0
- package/dist/src/figma/url-parser.js.map +1 -0
- package/dist/src/platform/device-manager.d.ts +5 -0
- package/dist/src/platform/device-manager.d.ts.map +1 -1
- package/dist/src/platform/device-manager.js +18 -0
- package/dist/src/platform/device-manager.js.map +1 -1
- package/dist/src/platform/device-pool.d.ts +105 -0
- package/dist/src/platform/device-pool.d.ts.map +1 -0
- package/dist/src/platform/device-pool.js +328 -0
- package/dist/src/platform/device-pool.js.map +1 -0
- package/dist/src/platform/device-profiles.d.ts +50 -0
- package/dist/src/platform/device-profiles.d.ts.map +1 -0
- package/dist/src/platform/device-profiles.js +155 -0
- package/dist/src/platform/device-profiles.js.map +1 -0
- package/dist/src/platform/ios/ios-device.d.ts +0 -2
- package/dist/src/platform/ios/ios-device.d.ts.map +1 -1
- package/dist/src/platform/ios/ios-device.js +8 -18
- package/dist/src/platform/ios/ios-device.js.map +1 -1
- package/dist/src/platform/ios/simctl.d.ts +0 -5
- package/dist/src/platform/ios/simctl.d.ts.map +1 -1
- package/dist/src/platform/ios/simctl.js +0 -4
- package/dist/src/platform/ios/simctl.js.map +1 -1
- package/dist/src/platform/simulator-factory.d.ts +85 -0
- package/dist/src/platform/simulator-factory.d.ts.map +1 -0
- package/dist/src/platform/simulator-factory.js +396 -0
- package/dist/src/platform/simulator-factory.js.map +1 -0
- package/dist/src/platform/system-resources.d.ts +44 -0
- package/dist/src/platform/system-resources.d.ts.map +1 -0
- package/dist/src/platform/system-resources.js +103 -0
- package/dist/src/platform/system-resources.js.map +1 -0
- package/dist/src/prototype/browser-engine.d.ts +62 -0
- package/dist/src/prototype/browser-engine.d.ts.map +1 -0
- package/dist/src/prototype/browser-engine.js +199 -0
- package/dist/src/prototype/browser-engine.js.map +1 -0
- package/dist/src/prototype/figma-navigator.d.ts +40 -0
- package/dist/src/prototype/figma-navigator.d.ts.map +1 -0
- package/dist/src/prototype/figma-navigator.js +95 -0
- package/dist/src/prototype/figma-navigator.js.map +1 -0
- package/dist/src/prototype/flow-reporter.d.ts +47 -0
- package/dist/src/prototype/flow-reporter.d.ts.map +1 -0
- package/dist/src/prototype/flow-reporter.js +255 -0
- package/dist/src/prototype/flow-reporter.js.map +1 -0
- package/dist/src/prototype/screen-analyzer.d.ts +31 -0
- package/dist/src/prototype/screen-analyzer.d.ts.map +1 -0
- package/dist/src/prototype/screen-analyzer.js +114 -0
- package/dist/src/prototype/screen-analyzer.js.map +1 -0
- package/dist/src/prototype/web-crawler.d.ts +31 -0
- package/dist/src/prototype/web-crawler.d.ts.map +1 -0
- package/dist/src/prototype/web-crawler.js +88 -0
- package/dist/src/prototype/web-crawler.js.map +1 -0
- package/dist/src/reports/cross-device-report.d.ts +84 -0
- package/dist/src/reports/cross-device-report.d.ts.map +1 -0
- package/dist/src/reports/cross-device-report.js +342 -0
- package/dist/src/reports/cross-device-report.js.map +1 -0
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +9 -1
- package/dist/src/server.js.map +1 -1
- package/dist/src/snapshot/formatter.d.ts +5 -13
- package/dist/src/snapshot/formatter.d.ts.map +1 -1
- package/dist/src/snapshot/formatter.js +19 -28
- package/dist/src/snapshot/formatter.js.map +1 -1
- package/dist/src/tools/interaction-tools.d.ts +6 -6
- package/dist/src/tools/interaction-tools.d.ts.map +1 -1
- package/dist/src/tools/interaction-tools.js +2 -12
- package/dist/src/tools/interaction-tools.js.map +1 -1
- package/dist/src/tools/metro-tools.d.ts +2 -2
- package/dist/src/tools/multi-device-tools.d.ts +133 -0
- package/dist/src/tools/multi-device-tools.d.ts.map +1 -0
- package/dist/src/tools/multi-device-tools.js +365 -0
- package/dist/src/tools/multi-device-tools.js.map +1 -0
- package/dist/src/tools/navigation-tools.d.ts.map +1 -1
- package/dist/src/tools/navigation-tools.js +1 -6
- package/dist/src/tools/navigation-tools.js.map +1 -1
- package/dist/src/tools/prototype-tools.d.ts +102 -0
- package/dist/src/tools/prototype-tools.d.ts.map +1 -0
- package/dist/src/tools/prototype-tools.js +391 -0
- package/dist/src/tools/prototype-tools.js.map +1 -0
- package/dist/src/tools/screenshot-tools.d.ts +7 -74
- package/dist/src/tools/screenshot-tools.d.ts.map +1 -1
- package/dist/src/tools/screenshot-tools.js +19 -286
- package/dist/src/tools/screenshot-tools.js.map +1 -1
- package/dist/src/tools/vqa-tools.d.ts +2 -2
- package/dist/src/tools/vqa-tools.d.ts.map +1 -1
- package/dist/src/tools/vqa-tools.js +4 -69
- package/dist/src/tools/vqa-tools.js.map +1 -1
- package/docs/figma-workflow.md +58 -6
- package/docs/installation-guide.md +302 -0
- package/docs/setup-guide.md +77 -79
- package/docs/tool-reference.md +152 -69
- package/install.sh +119 -0
- package/package.json +5 -2
- package/setup.sh +320 -0
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* DevLens MCP — Interactive Setup
|
|
5
|
+
*
|
|
6
|
+
* Configures npm authentication for Azure Artifacts and
|
|
7
|
+
* registers DevLens in Cursor / Claude Desktop / Claude Code.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npx devlens-mcp-setup (after npm is configured)
|
|
11
|
+
* node dist/bin/setup.js (from source)
|
|
12
|
+
* devlens-mcp setup (if globally installed)
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const fs_1 = require("fs");
|
|
16
|
+
const path_1 = require("path");
|
|
17
|
+
const readline_1 = require("readline");
|
|
18
|
+
const child_process_1 = require("child_process");
|
|
19
|
+
const AZURE_REGISTRY = "https://pkgs.dev.azure.com/JioOmni/_packaging/devlens/npm/registry/";
|
|
20
|
+
const AZURE_FEED_URL = "https://dev.azure.com/JioOmni/OmniAI/_artifacts/feed/devlens";
|
|
21
|
+
const PAT_URL = "https://dev.azure.com/JioOmni/_usersSettings/tokens";
|
|
22
|
+
const HOME = process.env.HOME || process.env.USERPROFILE || "~";
|
|
23
|
+
const IDE_TARGETS = [
|
|
24
|
+
{
|
|
25
|
+
name: "Cursor (global)",
|
|
26
|
+
configPath: (0, path_1.resolve)(HOME, ".cursor", "mcp.json"),
|
|
27
|
+
configKey: "mcpServers",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "Claude Desktop (macOS)",
|
|
31
|
+
configPath: (0, path_1.resolve)(HOME, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
32
|
+
configKey: "mcpServers",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "Claude Code",
|
|
36
|
+
configPath: (0, path_1.resolve)(HOME, ".claude", "mcp.json"),
|
|
37
|
+
configKey: "mcpServers",
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
function prompt(question) {
|
|
41
|
+
const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
|
|
42
|
+
return new Promise((answer) => {
|
|
43
|
+
rl.question(question, (val) => {
|
|
44
|
+
rl.close();
|
|
45
|
+
answer(val.trim());
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function log(msg) {
|
|
50
|
+
console.log(msg);
|
|
51
|
+
}
|
|
52
|
+
function success(msg) {
|
|
53
|
+
console.log(` [OK] ${msg}`);
|
|
54
|
+
}
|
|
55
|
+
function warn(msg) {
|
|
56
|
+
console.log(` [!!] ${msg}`);
|
|
57
|
+
}
|
|
58
|
+
function info(msg) {
|
|
59
|
+
console.log(` [..] ${msg}`);
|
|
60
|
+
}
|
|
61
|
+
function banner() {
|
|
62
|
+
log("");
|
|
63
|
+
log(" ╔══════════════════════════════════════════╗");
|
|
64
|
+
log(" ║ DevLens MCP — Setup Wizard ║");
|
|
65
|
+
log(" ╚══════════════════════════════════════════╝");
|
|
66
|
+
log("");
|
|
67
|
+
}
|
|
68
|
+
function checkNodeVersion() {
|
|
69
|
+
const [major] = process.versions.node.split(".").map(Number);
|
|
70
|
+
if (major < 18) {
|
|
71
|
+
warn(`Node.js ${process.versions.node} detected — v18+ required.`);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
success(`Node.js ${process.versions.node}`);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
function checkAdb() {
|
|
78
|
+
try {
|
|
79
|
+
(0, child_process_1.execFileSync)("adb", ["version"], { stdio: "pipe" });
|
|
80
|
+
success("Android SDK (adb) found");
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
info("Android SDK (adb) not found — Android features will be unavailable");
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function checkXcrun() {
|
|
89
|
+
if (process.platform !== "darwin")
|
|
90
|
+
return false;
|
|
91
|
+
try {
|
|
92
|
+
(0, child_process_1.execFileSync)("xcrun", ["simctl", "help"], { stdio: "pipe" });
|
|
93
|
+
success("Xcode simctl found");
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
info("Xcode simctl not found — iOS features will be unavailable");
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function configureNpmAuth(pat) {
|
|
102
|
+
const base64Pat = Buffer.from(pat).toString("base64");
|
|
103
|
+
const npmrcPath = (0, path_1.resolve)(HOME, ".npmrc");
|
|
104
|
+
let npmrcContent = "";
|
|
105
|
+
if ((0, fs_1.existsSync)(npmrcPath)) {
|
|
106
|
+
npmrcContent = (0, fs_1.readFileSync)(npmrcPath, "utf-8");
|
|
107
|
+
}
|
|
108
|
+
const registryKey = `//pkgs.dev.azure.com/JioOmni/_packaging/devlens/npm/registry/`;
|
|
109
|
+
const lines = npmrcContent.split("\n").filter((line) => {
|
|
110
|
+
return !line.includes("pkgs.dev.azure.com/JioOmni/_packaging/devlens");
|
|
111
|
+
});
|
|
112
|
+
lines.push(`${registryKey}:username=JioOmni`, `${registryKey}:_password=${base64Pat}`, `${registryKey}:email=npm@jio.com`, "");
|
|
113
|
+
(0, fs_1.writeFileSync)(npmrcPath, lines.join("\n"));
|
|
114
|
+
success(`npm credentials saved to ${npmrcPath}`);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
function devlensServerConfig() {
|
|
118
|
+
return {
|
|
119
|
+
command: "devlens-mcp",
|
|
120
|
+
args: [],
|
|
121
|
+
env: {
|
|
122
|
+
METRO_PORT: "8081",
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function configureIde(target, figmaToken) {
|
|
127
|
+
const dir = (0, path_1.dirname)(target.configPath);
|
|
128
|
+
let config = {};
|
|
129
|
+
if ((0, fs_1.existsSync)(target.configPath)) {
|
|
130
|
+
try {
|
|
131
|
+
config = JSON.parse((0, fs_1.readFileSync)(target.configPath, "utf-8"));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
config = {};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!config[target.configKey]) {
|
|
138
|
+
config[target.configKey] = {};
|
|
139
|
+
}
|
|
140
|
+
const serverConfig = devlensServerConfig();
|
|
141
|
+
if (figmaToken) {
|
|
142
|
+
serverConfig.env.FIGMA_TOKEN = figmaToken;
|
|
143
|
+
}
|
|
144
|
+
if (config[target.configKey].devlens) {
|
|
145
|
+
info(`${target.name}: DevLens already configured — updating`);
|
|
146
|
+
}
|
|
147
|
+
config[target.configKey].devlens = serverConfig;
|
|
148
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
149
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
150
|
+
}
|
|
151
|
+
(0, fs_1.writeFileSync)(target.configPath, JSON.stringify(config, null, 2) + "\n");
|
|
152
|
+
success(`${target.name}: configured`);
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
function createProjectNpmrc(projectDir) {
|
|
156
|
+
const dir = projectDir || process.cwd();
|
|
157
|
+
const npmrcPath = (0, path_1.resolve)(dir, ".npmrc");
|
|
158
|
+
if ((0, fs_1.existsSync)(npmrcPath)) {
|
|
159
|
+
const content = (0, fs_1.readFileSync)(npmrcPath, "utf-8");
|
|
160
|
+
if (content.includes("pkgs.dev.azure.com/JioOmni/_packaging/devlens")) {
|
|
161
|
+
success(`Project .npmrc already configured at ${npmrcPath}`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const content = [
|
|
166
|
+
`registry=${AZURE_REGISTRY}`,
|
|
167
|
+
"always-auth=true",
|
|
168
|
+
"",
|
|
169
|
+
].join("\n");
|
|
170
|
+
(0, fs_1.writeFileSync)(npmrcPath, content);
|
|
171
|
+
success(`Project .npmrc created at ${npmrcPath}`);
|
|
172
|
+
}
|
|
173
|
+
async function main() {
|
|
174
|
+
banner();
|
|
175
|
+
log(" Step 1/6 — Checking prerequisites");
|
|
176
|
+
log(" ──────────────────────────────────");
|
|
177
|
+
const nodeOk = checkNodeVersion();
|
|
178
|
+
if (!nodeOk) {
|
|
179
|
+
log("\n Please install Node.js 18+ and try again.");
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
checkAdb();
|
|
183
|
+
checkXcrun();
|
|
184
|
+
log("");
|
|
185
|
+
log(" Step 2/6 — Azure Artifacts authentication");
|
|
186
|
+
log(" ──────────────────────────────────────────");
|
|
187
|
+
log(` Create a PAT at: ${PAT_URL}`);
|
|
188
|
+
log(" Required scope: Packaging → Read");
|
|
189
|
+
log("");
|
|
190
|
+
const pat = await prompt(" Paste your Azure DevOps PAT: ");
|
|
191
|
+
if (!pat || pat.length < 20) {
|
|
192
|
+
warn("Invalid PAT. Please generate one and try again.");
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
await configureNpmAuth(pat);
|
|
196
|
+
log("");
|
|
197
|
+
log(" Step 3/6 — Installing DevLens globally");
|
|
198
|
+
log(" ───────────────────────────────────────");
|
|
199
|
+
try {
|
|
200
|
+
(0, child_process_1.execFileSync)("npm", [
|
|
201
|
+
"install",
|
|
202
|
+
"-g",
|
|
203
|
+
"devlens-mcp@latest",
|
|
204
|
+
"--registry",
|
|
205
|
+
AZURE_REGISTRY,
|
|
206
|
+
], { stdio: "inherit" });
|
|
207
|
+
const version = (0, child_process_1.execFileSync)("devlens-mcp", ["--version"], {
|
|
208
|
+
encoding: "utf-8",
|
|
209
|
+
}).trim();
|
|
210
|
+
success(`devlens-mcp installed globally (${version})`);
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
warn("Global install failed — check PAT permissions");
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
log("");
|
|
217
|
+
log(" Step 4/6 — Project npm configuration");
|
|
218
|
+
log(" ────────────────────────────────────");
|
|
219
|
+
createProjectNpmrc();
|
|
220
|
+
log("");
|
|
221
|
+
log(" Step 5/6 — IDE configuration");
|
|
222
|
+
log(" ────────────────────────────");
|
|
223
|
+
const figmaToken = await prompt(" Figma token (optional, press Enter to skip): ");
|
|
224
|
+
const configuredIdes = [];
|
|
225
|
+
for (const target of IDE_TARGETS) {
|
|
226
|
+
const parentDir = (0, path_1.dirname)(target.configPath);
|
|
227
|
+
const parentExists = (0, fs_1.existsSync)(parentDir) || (0, fs_1.existsSync)((0, path_1.dirname)(parentDir));
|
|
228
|
+
if (target.name.includes("macOS") && process.platform !== "darwin") {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (parentExists ||
|
|
232
|
+
target.name.includes("Cursor")) {
|
|
233
|
+
configureIde(target, figmaToken || undefined);
|
|
234
|
+
configuredIdes.push(target.name);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (configuredIdes.length === 0) {
|
|
238
|
+
warn("No supported IDEs detected. You can configure manually later.");
|
|
239
|
+
}
|
|
240
|
+
log("");
|
|
241
|
+
log(" Step 6/6 — Verification");
|
|
242
|
+
log(" ───────────────────────");
|
|
243
|
+
try {
|
|
244
|
+
const version = (0, child_process_1.execFileSync)("devlens-mcp", ["--version"], {
|
|
245
|
+
encoding: "utf-8",
|
|
246
|
+
stdio: "pipe",
|
|
247
|
+
}).trim();
|
|
248
|
+
success(`DevLens CLI works: ${version}`);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
warn("Could not verify devlens-mcp command.");
|
|
252
|
+
info("Try running: devlens-mcp --version");
|
|
253
|
+
}
|
|
254
|
+
log("");
|
|
255
|
+
log(" ╔══════════════════════════════════════════╗");
|
|
256
|
+
log(" ║ Setup Complete! ║");
|
|
257
|
+
log(" ╚══════════════════════════════════════════╝");
|
|
258
|
+
log("");
|
|
259
|
+
log(" What's next:");
|
|
260
|
+
log(" 1. Restart Cursor / Claude Desktop");
|
|
261
|
+
log(" 2. Start your React Native app (npx react-native start)");
|
|
262
|
+
log(" 3. Start an emulator/simulator");
|
|
263
|
+
log(" 4. Ask the AI: \"List running devices\"");
|
|
264
|
+
log("");
|
|
265
|
+
log(` Feed: ${AZURE_FEED_URL}`);
|
|
266
|
+
log("");
|
|
267
|
+
}
|
|
268
|
+
main().catch((err) => {
|
|
269
|
+
console.error("Setup failed:", err.message);
|
|
270
|
+
process.exit(1);
|
|
271
|
+
});
|
|
272
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../bin/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { FigmaRateLimitError } from "./figma-types.js";
|
|
2
|
+
import type { FigmaClient } from "./figma-client.js";
|
|
3
|
+
export { FigmaRateLimitError };
|
|
4
|
+
export interface PrototypeConnection {
|
|
5
|
+
sourceNodeId: string;
|
|
6
|
+
sourceNodeName: string;
|
|
7
|
+
destinationNodeId: string;
|
|
8
|
+
trigger: string;
|
|
9
|
+
action: string;
|
|
10
|
+
transitionType?: string;
|
|
11
|
+
transitionDuration?: number;
|
|
12
|
+
transitionEasing?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PrototypeFlowSummary {
|
|
15
|
+
hasPrototype: boolean;
|
|
16
|
+
startingNodeId?: string;
|
|
17
|
+
startingNodeName?: string;
|
|
18
|
+
screenCount: number;
|
|
19
|
+
connections: PrototypeConnection[];
|
|
20
|
+
allScreenIds: string[];
|
|
21
|
+
allScreenNames: Map<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export interface FigmaFileData {
|
|
24
|
+
name: string;
|
|
25
|
+
document: FigmaNode;
|
|
26
|
+
schemaVersion: number;
|
|
27
|
+
}
|
|
28
|
+
export interface FigmaNode {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
type: string;
|
|
32
|
+
children?: FigmaNode[];
|
|
33
|
+
prototypeStartNodeID?: string;
|
|
34
|
+
flowStartingPoints?: Array<{
|
|
35
|
+
nodeId: string;
|
|
36
|
+
name: string;
|
|
37
|
+
}>;
|
|
38
|
+
transitionNodeID?: string;
|
|
39
|
+
transitionDuration?: number;
|
|
40
|
+
transitionEasing?: {
|
|
41
|
+
type: string;
|
|
42
|
+
};
|
|
43
|
+
reactions?: FigmaReaction[];
|
|
44
|
+
absoluteBoundingBox?: {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
width: number;
|
|
48
|
+
height: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export interface FigmaReaction {
|
|
52
|
+
trigger: {
|
|
53
|
+
type: string;
|
|
54
|
+
};
|
|
55
|
+
actions?: Array<{
|
|
56
|
+
type: string;
|
|
57
|
+
destinationId?: string;
|
|
58
|
+
navigation?: string;
|
|
59
|
+
transition?: {
|
|
60
|
+
type: string;
|
|
61
|
+
duration: number;
|
|
62
|
+
easing?: {
|
|
63
|
+
type: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Fetch Figma file data including prototype information.
|
|
70
|
+
* Uses depth=2 by default to keep payload manageable while still
|
|
71
|
+
* capturing top-level frames and their direct children.
|
|
72
|
+
*/
|
|
73
|
+
export declare function fetchFileData(fileKey: string, token?: string, client?: FigmaClient): Promise<FigmaFileData>;
|
|
74
|
+
/**
|
|
75
|
+
* Fetch full file data (no depth limit) for thorough prototype
|
|
76
|
+
* connection extraction.
|
|
77
|
+
*/
|
|
78
|
+
export declare function fetchFileDataFull(fileKey: string, token?: string, client?: FigmaClient): Promise<FigmaFileData>;
|
|
79
|
+
/**
|
|
80
|
+
* Quick boolean check: does this file have prototype connections?
|
|
81
|
+
*/
|
|
82
|
+
export declare function hasPrototypeConnections(fileData: FigmaFileData): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Walk the Figma node tree and extract all prototype connections
|
|
85
|
+
* (reactions that navigate to other frames).
|
|
86
|
+
*/
|
|
87
|
+
export declare function extractPrototypeFlows(fileData: FigmaFileData): PrototypeFlowSummary;
|
|
88
|
+
/**
|
|
89
|
+
* Batch-export node images via the Figma images endpoint.
|
|
90
|
+
* Returns a map of nodeId -> image URL.
|
|
91
|
+
*/
|
|
92
|
+
export declare function exportNodeScreenshots(fileKey: string, nodeIds: readonly string[], scale?: number, token?: string, client?: FigmaClient): Promise<Map<string, string>>;
|
|
93
|
+
/**
|
|
94
|
+
* Resolve a Figma design URL (or fileKey+nodeId) to a PNG buffer.
|
|
95
|
+
* Shared helper extracted from the inline implementations in
|
|
96
|
+
* screenshot-tools and vqa-tools.
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveFigmaImage(params: {
|
|
99
|
+
figmaUrl?: string;
|
|
100
|
+
fileKey?: string;
|
|
101
|
+
nodeId?: string;
|
|
102
|
+
scale: number;
|
|
103
|
+
client?: FigmaClient;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
buffer: Buffer;
|
|
106
|
+
error?: string;
|
|
107
|
+
}>;
|
|
108
|
+
//# sourceMappingURL=figma-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-api.d.ts","sourceRoot":"","sources":["../../../src/figma/figma-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FigmaRateLimitError = void 0;
|
|
4
|
+
exports.fetchFileData = fetchFileData;
|
|
5
|
+
exports.fetchFileDataFull = fetchFileDataFull;
|
|
6
|
+
exports.hasPrototypeConnections = hasPrototypeConnections;
|
|
7
|
+
exports.extractPrototypeFlows = extractPrototypeFlows;
|
|
8
|
+
exports.exportNodeScreenshots = exportNodeScreenshots;
|
|
9
|
+
exports.resolveFigmaImage = resolveFigmaImage;
|
|
10
|
+
const url_parser_js_1 = require("./url-parser.js");
|
|
11
|
+
const figma_types_js_1 = require("./figma-types.js");
|
|
12
|
+
Object.defineProperty(exports, "FigmaRateLimitError", { enumerable: true, get: function () { return figma_types_js_1.FigmaRateLimitError; } });
|
|
13
|
+
const API_BASE = "https://api.figma.com/v1";
|
|
14
|
+
const REQUEST_TIMEOUT_MS = 20_000;
|
|
15
|
+
function getFigmaToken() {
|
|
16
|
+
const token = process.env.FIGMA_TOKEN;
|
|
17
|
+
if (!token) {
|
|
18
|
+
throw new Error("FIGMA_TOKEN environment variable is not set.\n" +
|
|
19
|
+
'Set it in your MCP config: "env": { "FIGMA_TOKEN": "figd_xxxxx" }\n' +
|
|
20
|
+
"Generate at: https://www.figma.com/developers/api#access-tokens");
|
|
21
|
+
}
|
|
22
|
+
return token;
|
|
23
|
+
}
|
|
24
|
+
async function figmaFetch(path, token) {
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetch(`${API_BASE}${path}`, {
|
|
29
|
+
headers: { "X-Figma-Token": token },
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
});
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
if (response.status === 429) {
|
|
34
|
+
const info = (0, figma_types_js_1.parseRateLimitHeaders)(response);
|
|
35
|
+
if (info) {
|
|
36
|
+
throw new figma_types_js_1.FigmaRateLimitError(`Figma API rate limited (retry-after: ${info.retryAfterSeconds}s)`, info);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const body = await response.text().catch(() => "");
|
|
41
|
+
throw new Error(`Figma API ${response.status}: ${body || response.statusText}`);
|
|
42
|
+
}
|
|
43
|
+
return (await response.json());
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
clearTimeout(timeout);
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Fetch Figma file data including prototype information.
|
|
52
|
+
* Uses depth=2 by default to keep payload manageable while still
|
|
53
|
+
* capturing top-level frames and their direct children.
|
|
54
|
+
*/
|
|
55
|
+
async function fetchFileData(fileKey, token, client) {
|
|
56
|
+
const t = token ?? getFigmaToken();
|
|
57
|
+
if (client) {
|
|
58
|
+
return client.fetchFileData(fileKey, t);
|
|
59
|
+
}
|
|
60
|
+
return figmaFetch(`/files/${fileKey}?depth=2`, t);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fetch full file data (no depth limit) for thorough prototype
|
|
64
|
+
* connection extraction.
|
|
65
|
+
*/
|
|
66
|
+
async function fetchFileDataFull(fileKey, token, client) {
|
|
67
|
+
const t = token ?? getFigmaToken();
|
|
68
|
+
if (client) {
|
|
69
|
+
return client.fetchFileDataFull(fileKey, t);
|
|
70
|
+
}
|
|
71
|
+
return figmaFetch(`/files/${fileKey}`, t);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Quick boolean check: does this file have prototype connections?
|
|
75
|
+
*/
|
|
76
|
+
function hasPrototypeConnections(fileData) {
|
|
77
|
+
const summary = extractPrototypeFlows(fileData);
|
|
78
|
+
return summary.hasPrototype;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Walk the Figma node tree and extract all prototype connections
|
|
82
|
+
* (reactions that navigate to other frames).
|
|
83
|
+
*/
|
|
84
|
+
function extractPrototypeFlows(fileData) {
|
|
85
|
+
const connections = [];
|
|
86
|
+
const screenNames = new Map();
|
|
87
|
+
const screenIds = new Set();
|
|
88
|
+
let startingNodeId;
|
|
89
|
+
let startingNodeName;
|
|
90
|
+
function walkNode(node) {
|
|
91
|
+
if (node.type === "FRAME" || node.type === "COMPONENT") {
|
|
92
|
+
screenNames.set(node.id, node.name);
|
|
93
|
+
}
|
|
94
|
+
if (node.flowStartingPoints && node.flowStartingPoints.length > 0) {
|
|
95
|
+
const sp = node.flowStartingPoints[0];
|
|
96
|
+
startingNodeId = sp.nodeId;
|
|
97
|
+
startingNodeName = sp.name;
|
|
98
|
+
}
|
|
99
|
+
if (node.prototypeStartNodeID && !startingNodeId) {
|
|
100
|
+
startingNodeId = node.prototypeStartNodeID;
|
|
101
|
+
}
|
|
102
|
+
if (node.reactions) {
|
|
103
|
+
for (const reaction of node.reactions) {
|
|
104
|
+
if (!reaction.actions)
|
|
105
|
+
continue;
|
|
106
|
+
for (const action of reaction.actions) {
|
|
107
|
+
if (action.destinationId) {
|
|
108
|
+
screenIds.add(node.id);
|
|
109
|
+
screenIds.add(action.destinationId);
|
|
110
|
+
connections.push({
|
|
111
|
+
sourceNodeId: node.id,
|
|
112
|
+
sourceNodeName: node.name,
|
|
113
|
+
destinationNodeId: action.destinationId,
|
|
114
|
+
trigger: reaction.trigger.type,
|
|
115
|
+
action: action.type,
|
|
116
|
+
transitionType: action.transition?.type,
|
|
117
|
+
transitionDuration: action.transition?.duration,
|
|
118
|
+
transitionEasing: action.transition?.easing?.type,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (node.transitionNodeID) {
|
|
125
|
+
screenIds.add(node.id);
|
|
126
|
+
screenIds.add(node.transitionNodeID);
|
|
127
|
+
connections.push({
|
|
128
|
+
sourceNodeId: node.id,
|
|
129
|
+
sourceNodeName: node.name,
|
|
130
|
+
destinationNodeId: node.transitionNodeID,
|
|
131
|
+
trigger: "ON_CLICK",
|
|
132
|
+
action: "NAVIGATE",
|
|
133
|
+
transitionDuration: node.transitionDuration,
|
|
134
|
+
transitionEasing: node.transitionEasing?.type,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (node.children) {
|
|
138
|
+
for (const child of node.children) {
|
|
139
|
+
walkNode(child);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
walkNode(fileData.document);
|
|
144
|
+
if (!startingNodeName && startingNodeId) {
|
|
145
|
+
startingNodeName = screenNames.get(startingNodeId);
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
hasPrototype: connections.length > 0,
|
|
149
|
+
startingNodeId,
|
|
150
|
+
startingNodeName,
|
|
151
|
+
screenCount: screenIds.size,
|
|
152
|
+
connections,
|
|
153
|
+
allScreenIds: [...screenIds],
|
|
154
|
+
allScreenNames: screenNames,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Batch-export node images via the Figma images endpoint.
|
|
159
|
+
* Returns a map of nodeId -> image URL.
|
|
160
|
+
*/
|
|
161
|
+
async function exportNodeScreenshots(fileKey, nodeIds, scale = 2, token, client) {
|
|
162
|
+
const t = token ?? getFigmaToken();
|
|
163
|
+
if (client) {
|
|
164
|
+
return client.exportImages(fileKey, [...nodeIds], scale, t);
|
|
165
|
+
}
|
|
166
|
+
const idsParam = nodeIds
|
|
167
|
+
.map((id) => encodeURIComponent((0, url_parser_js_1.normalizeNodeId)(id)))
|
|
168
|
+
.join(",");
|
|
169
|
+
const data = await figmaFetch(`/images/${fileKey}?ids=${idsParam}&format=png&scale=${scale}`, t);
|
|
170
|
+
if (data.err) {
|
|
171
|
+
throw new Error(`Figma image export error: ${data.err}`);
|
|
172
|
+
}
|
|
173
|
+
const result = new Map();
|
|
174
|
+
for (const [id, url] of Object.entries(data.images)) {
|
|
175
|
+
if (url)
|
|
176
|
+
result.set(id, url);
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Resolve a Figma design URL (or fileKey+nodeId) to a PNG buffer.
|
|
182
|
+
* Shared helper extracted from the inline implementations in
|
|
183
|
+
* screenshot-tools and vqa-tools.
|
|
184
|
+
*/
|
|
185
|
+
async function resolveFigmaImage(params) {
|
|
186
|
+
const figmaToken = process.env.FIGMA_TOKEN;
|
|
187
|
+
if (!figmaToken) {
|
|
188
|
+
return {
|
|
189
|
+
buffer: Buffer.alloc(0),
|
|
190
|
+
error: "FIGMA_TOKEN environment variable is not set. Required for Figma image resolution.",
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
let fileKey = params.fileKey;
|
|
194
|
+
let nodeId = params.nodeId;
|
|
195
|
+
if (params.figmaUrl) {
|
|
196
|
+
const parsed = (0, url_parser_js_1.parseFigmaUrl)(params.figmaUrl);
|
|
197
|
+
if (!parsed) {
|
|
198
|
+
return {
|
|
199
|
+
buffer: Buffer.alloc(0),
|
|
200
|
+
error: `Could not parse Figma URL: ${params.figmaUrl}`,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
fileKey = parsed.fileKey;
|
|
204
|
+
nodeId = parsed.nodeId;
|
|
205
|
+
}
|
|
206
|
+
if (!fileKey || !nodeId) {
|
|
207
|
+
return {
|
|
208
|
+
buffer: Buffer.alloc(0),
|
|
209
|
+
error: "Provide either figmaUrl, or both fileKey and nodeId.",
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
// Use FigmaClient if provided — gets caching, rate limiting, retry for free
|
|
213
|
+
if (params.client) {
|
|
214
|
+
const result = await params.client.resolveImage({
|
|
215
|
+
fileKey,
|
|
216
|
+
nodeId,
|
|
217
|
+
scale: params.scale,
|
|
218
|
+
token: figmaToken,
|
|
219
|
+
});
|
|
220
|
+
if ("error" in result) {
|
|
221
|
+
return { buffer: Buffer.alloc(0), error: result.error };
|
|
222
|
+
}
|
|
223
|
+
return { buffer: result.buffer };
|
|
224
|
+
}
|
|
225
|
+
// Legacy path — direct fetch (no caching/rate limiting)
|
|
226
|
+
const normalizedNodeId = (0, url_parser_js_1.normalizeNodeId)(nodeId);
|
|
227
|
+
const apiUrl = `${API_BASE}/images/${fileKey}?ids=${encodeURIComponent(normalizedNodeId)}&format=png&scale=${params.scale}`;
|
|
228
|
+
const controller = new AbortController();
|
|
229
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
230
|
+
try {
|
|
231
|
+
const apiResponse = await fetch(apiUrl, {
|
|
232
|
+
headers: { "X-Figma-Token": figmaToken },
|
|
233
|
+
signal: controller.signal,
|
|
234
|
+
});
|
|
235
|
+
clearTimeout(timeout);
|
|
236
|
+
if (apiResponse.status === 429) {
|
|
237
|
+
const info = (0, figma_types_js_1.parseRateLimitHeaders)(apiResponse);
|
|
238
|
+
if (info) {
|
|
239
|
+
let msg = `Figma API rate limit exceeded. Try again in ${info.retryAfterSeconds}s.`;
|
|
240
|
+
if (info.rateLimitType === "low") {
|
|
241
|
+
msg = `Your Figma seat has limited API access (View/Collab: ~6 req/month). ` +
|
|
242
|
+
`Upgrade to Full/Dev seat for 10-20 req/min.`;
|
|
243
|
+
if (info.upgradeLink)
|
|
244
|
+
msg += `\nUpgrade: ${info.upgradeLink}`;
|
|
245
|
+
}
|
|
246
|
+
return { buffer: Buffer.alloc(0), error: msg };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (!apiResponse.ok) {
|
|
250
|
+
return {
|
|
251
|
+
buffer: Buffer.alloc(0),
|
|
252
|
+
error: `Figma API error (${apiResponse.status})`,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
const apiData = (await apiResponse.json());
|
|
256
|
+
if (apiData.err) {
|
|
257
|
+
return {
|
|
258
|
+
buffer: Buffer.alloc(0),
|
|
259
|
+
error: `Figma API: ${apiData.err}`,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
const imageUrl = Object.values(apiData.images)[0];
|
|
263
|
+
if (!imageUrl) {
|
|
264
|
+
return {
|
|
265
|
+
buffer: Buffer.alloc(0),
|
|
266
|
+
error: `No image returned for node ${normalizedNodeId}`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const imgResponse = await fetch(imageUrl);
|
|
270
|
+
if (!imgResponse.ok) {
|
|
271
|
+
return {
|
|
272
|
+
buffer: Buffer.alloc(0),
|
|
273
|
+
error: `Failed to download Figma image: ${imgResponse.status}`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
return { buffer: Buffer.from(await imgResponse.arrayBuffer()) };
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
clearTimeout(timeout);
|
|
280
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
281
|
+
return { buffer: Buffer.alloc(0), error: `Figma fetch failed: ${msg}` };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=figma-api.js.map
|