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,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive token-bucket rate limiter for the Figma API.
|
|
3
|
+
* Starts conservative (10 req/min), auto-adapts when 429 headers
|
|
4
|
+
* reveal the user's plan tier and seat type.
|
|
5
|
+
*/
|
|
6
|
+
import { type FigmaRateLimitInfo, type RateLimiterStatus } from "./figma-types.js";
|
|
7
|
+
export declare class FigmaRateLimiter {
|
|
8
|
+
private budget;
|
|
9
|
+
private tokens;
|
|
10
|
+
private lastRefill;
|
|
11
|
+
private pausedUntil;
|
|
12
|
+
private consecutiveSuccesses;
|
|
13
|
+
private planCap;
|
|
14
|
+
private detectedPlanTier?;
|
|
15
|
+
private detectedSeatType?;
|
|
16
|
+
private totalRequests;
|
|
17
|
+
private throttledRequests;
|
|
18
|
+
constructor(config?: {
|
|
19
|
+
initialBudget?: number;
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Wait until a request is allowed. Blocks if paused or no tokens.
|
|
23
|
+
* Throws FigmaRateLimitError for View/Collab seats (budget = 0).
|
|
24
|
+
*/
|
|
25
|
+
acquire(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Called when a 429 response is received. Adapts budget and pauses.
|
|
28
|
+
*/
|
|
29
|
+
onRateLimited(info: FigmaRateLimitInfo): void;
|
|
30
|
+
/**
|
|
31
|
+
* Called on successful API response. Gradually increases budget.
|
|
32
|
+
*/
|
|
33
|
+
onSuccess(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Check if currently rate-limited without blocking.
|
|
36
|
+
*/
|
|
37
|
+
isLimited(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Get status for logging/observability.
|
|
40
|
+
*/
|
|
41
|
+
getStatus(): RateLimiterStatus;
|
|
42
|
+
private refillTokens;
|
|
43
|
+
private msUntilNextToken;
|
|
44
|
+
private sleep;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=figma-rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-rate-limiter.d.ts","sourceRoot":"","sources":["../../../src/figma/figma-rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAgB1B,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,OAAO,CAAY;IAE3B,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,iBAAiB,CAAK;gBAElB,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE;IAM/C;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC9B;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAmC7C;;OAEG;IACH,SAAS,IAAI,IAAI;IAUjB;;OAEG;IACH,SAAS,IAAI,OAAO;IAKpB;;OAEG;IACH,SAAS,IAAI,iBAAiB;IAc9B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Adaptive token-bucket rate limiter for the Figma API.
|
|
4
|
+
* Starts conservative (10 req/min), auto-adapts when 429 headers
|
|
5
|
+
* reveal the user's plan tier and seat type.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.FigmaRateLimiter = void 0;
|
|
9
|
+
const figma_types_js_1 = require("./figma-types.js");
|
|
10
|
+
/** Plan-tier caps (requests per minute) */
|
|
11
|
+
const PLAN_CAPS = {
|
|
12
|
+
starter: 10,
|
|
13
|
+
pro: 15,
|
|
14
|
+
org: 20,
|
|
15
|
+
organization: 20,
|
|
16
|
+
enterprise: 30,
|
|
17
|
+
};
|
|
18
|
+
const DEFAULT_BUDGET = 10;
|
|
19
|
+
const BUDGET_INCREASE_THRESHOLD = 20; // consecutive successes before increasing
|
|
20
|
+
const BUDGET_INCREASE_STEP = 2;
|
|
21
|
+
const BUDGET_DECREASE_FACTOR = 0.7; // multiply by this on 429
|
|
22
|
+
class FigmaRateLimiter {
|
|
23
|
+
budget;
|
|
24
|
+
tokens;
|
|
25
|
+
lastRefill;
|
|
26
|
+
pausedUntil = 0;
|
|
27
|
+
consecutiveSuccesses = 0;
|
|
28
|
+
planCap = Infinity;
|
|
29
|
+
detectedPlanTier;
|
|
30
|
+
detectedSeatType;
|
|
31
|
+
totalRequests = 0;
|
|
32
|
+
throttledRequests = 0;
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.budget = config?.initialBudget ?? DEFAULT_BUDGET;
|
|
35
|
+
this.tokens = this.budget;
|
|
36
|
+
this.lastRefill = Date.now();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Wait until a request is allowed. Blocks if paused or no tokens.
|
|
40
|
+
* Throws FigmaRateLimitError for View/Collab seats (budget = 0).
|
|
41
|
+
*/
|
|
42
|
+
async acquire() {
|
|
43
|
+
this.totalRequests++;
|
|
44
|
+
this.refillTokens();
|
|
45
|
+
// If paused (after a 429), wait it out
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
if (this.pausedUntil > now) {
|
|
48
|
+
const waitMs = this.pausedUntil - now;
|
|
49
|
+
if (waitMs > 300_000) {
|
|
50
|
+
// More than 5 minutes — likely a View/Collab seat
|
|
51
|
+
throw new figma_types_js_1.FigmaRateLimitError("Figma API rate limit: long pause required (likely View/Collab seat).", {
|
|
52
|
+
retryAfterSeconds: Math.ceil(waitMs / 1000),
|
|
53
|
+
planTier: this.detectedPlanTier,
|
|
54
|
+
rateLimitType: this.detectedSeatType,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
this.throttledRequests++;
|
|
58
|
+
await this.sleep(waitMs);
|
|
59
|
+
}
|
|
60
|
+
// Wait for a token
|
|
61
|
+
while (this.tokens < 1) {
|
|
62
|
+
this.throttledRequests++;
|
|
63
|
+
const refillWait = this.msUntilNextToken();
|
|
64
|
+
await this.sleep(refillWait);
|
|
65
|
+
this.refillTokens();
|
|
66
|
+
}
|
|
67
|
+
this.tokens--;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Called when a 429 response is received. Adapts budget and pauses.
|
|
71
|
+
*/
|
|
72
|
+
onRateLimited(info) {
|
|
73
|
+
this.consecutiveSuccesses = 0;
|
|
74
|
+
// Detect plan tier from headers
|
|
75
|
+
if (info.planTier && !this.detectedPlanTier) {
|
|
76
|
+
this.detectedPlanTier = info.planTier.toLowerCase();
|
|
77
|
+
const cap = PLAN_CAPS[this.detectedPlanTier];
|
|
78
|
+
if (cap) {
|
|
79
|
+
this.planCap = cap;
|
|
80
|
+
this.budget = Math.min(this.budget, cap);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (info.rateLimitType && !this.detectedSeatType) {
|
|
84
|
+
this.detectedSeatType = info.rateLimitType.toLowerCase();
|
|
85
|
+
if (this.detectedSeatType === "low") {
|
|
86
|
+
// View/Collab seat — extremely limited (6 req/month)
|
|
87
|
+
this.budget = 0;
|
|
88
|
+
this.planCap = 0;
|
|
89
|
+
this.tokens = 0;
|
|
90
|
+
const pauseMs = info.retryAfterSeconds * 1000;
|
|
91
|
+
this.pausedUntil = Date.now() + pauseMs;
|
|
92
|
+
return; // Skip normal budget decrease
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Decrease budget
|
|
96
|
+
this.budget = Math.max(1, Math.floor(this.budget * BUDGET_DECREASE_FACTOR));
|
|
97
|
+
// Pause for the Retry-After duration
|
|
98
|
+
const pauseMs = info.retryAfterSeconds * 1000;
|
|
99
|
+
this.pausedUntil = Date.now() + pauseMs;
|
|
100
|
+
this.tokens = 0;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Called on successful API response. Gradually increases budget.
|
|
104
|
+
*/
|
|
105
|
+
onSuccess() {
|
|
106
|
+
this.consecutiveSuccesses++;
|
|
107
|
+
if (this.consecutiveSuccesses >= BUDGET_INCREASE_THRESHOLD) {
|
|
108
|
+
this.consecutiveSuccesses = 0;
|
|
109
|
+
const newBudget = this.budget + BUDGET_INCREASE_STEP;
|
|
110
|
+
this.budget = Math.min(newBudget, this.planCap);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if currently rate-limited without blocking.
|
|
115
|
+
*/
|
|
116
|
+
isLimited() {
|
|
117
|
+
this.refillTokens();
|
|
118
|
+
return Date.now() < this.pausedUntil || this.tokens < 1;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get status for logging/observability.
|
|
122
|
+
*/
|
|
123
|
+
getStatus() {
|
|
124
|
+
this.refillTokens();
|
|
125
|
+
return {
|
|
126
|
+
budget: this.budget,
|
|
127
|
+
tokens: Math.floor(this.tokens),
|
|
128
|
+
pausedUntil: this.pausedUntil,
|
|
129
|
+
detectedPlanTier: this.detectedPlanTier,
|
|
130
|
+
detectedSeatType: this.detectedSeatType,
|
|
131
|
+
totalRequests: this.totalRequests,
|
|
132
|
+
throttledRequests: this.throttledRequests,
|
|
133
|
+
isLimited: this.isLimited(),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
refillTokens() {
|
|
137
|
+
const now = Date.now();
|
|
138
|
+
const elapsed = now - this.lastRefill;
|
|
139
|
+
const refillAmount = (elapsed / 60_000) * this.budget;
|
|
140
|
+
this.tokens = Math.min(this.budget, this.tokens + refillAmount);
|
|
141
|
+
this.lastRefill = now;
|
|
142
|
+
}
|
|
143
|
+
msUntilNextToken() {
|
|
144
|
+
if (this.budget <= 0)
|
|
145
|
+
return 60_000;
|
|
146
|
+
return Math.ceil(60_000 / this.budget);
|
|
147
|
+
}
|
|
148
|
+
sleep(ms) {
|
|
149
|
+
return new Promise((resolve) => setTimeout(resolve, Math.min(ms, 60_000)));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.FigmaRateLimiter = FigmaRateLimiter;
|
|
153
|
+
//# sourceMappingURL=figma-rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-rate-limiter.js","sourceRoot":"","sources":["../../../src/figma/figma-rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 429-aware retry wrapper for Figma API requests.
|
|
3
|
+
* Respects Retry-After headers, delegates to the rate limiter,
|
|
4
|
+
* and uses exponential backoff for 5xx errors.
|
|
5
|
+
*/
|
|
6
|
+
import type { FigmaRateLimiter } from "./figma-rate-limiter.js";
|
|
7
|
+
export interface FigmaRetryOptions {
|
|
8
|
+
rateLimiter: FigmaRateLimiter;
|
|
9
|
+
maxAttempts?: number;
|
|
10
|
+
onRetry?: (attempt: number, delayMs: number, reason: string) => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Execute a fetch with rate limiting + retry.
|
|
14
|
+
* - 429: parse Retry-After, pause via rate limiter, retry
|
|
15
|
+
* - 5xx: exponential backoff (1s, 2s, 4s)
|
|
16
|
+
* - 4xx (non-429): throw immediately
|
|
17
|
+
*/
|
|
18
|
+
export declare function figmaRetry(fn: () => Promise<Response>, options: FigmaRetryOptions): Promise<Response>;
|
|
19
|
+
//# sourceMappingURL=figma-retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-retry.d.ts","sourceRoot":"","sources":["../../../src/figma/figma-retry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACtE;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,EAC3B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,QAAQ,CAAC,CAoDnB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 429-aware retry wrapper for Figma API requests.
|
|
4
|
+
* Respects Retry-After headers, delegates to the rate limiter,
|
|
5
|
+
* and uses exponential backoff for 5xx errors.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.figmaRetry = figmaRetry;
|
|
9
|
+
const figma_types_js_1 = require("./figma-types.js");
|
|
10
|
+
/**
|
|
11
|
+
* Execute a fetch with rate limiting + retry.
|
|
12
|
+
* - 429: parse Retry-After, pause via rate limiter, retry
|
|
13
|
+
* - 5xx: exponential backoff (1s, 2s, 4s)
|
|
14
|
+
* - 4xx (non-429): throw immediately
|
|
15
|
+
*/
|
|
16
|
+
async function figmaRetry(fn, options) {
|
|
17
|
+
const { rateLimiter, maxAttempts = 3, onRetry } = options;
|
|
18
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
19
|
+
await rateLimiter.acquire();
|
|
20
|
+
const response = await fn();
|
|
21
|
+
if (response.status === 429) {
|
|
22
|
+
const info = (0, figma_types_js_1.parseRateLimitHeaders)(response);
|
|
23
|
+
if (info) {
|
|
24
|
+
rateLimiter.onRateLimited(info);
|
|
25
|
+
// View/Collab seats or extremely long waits — don't retry
|
|
26
|
+
if (info.retryAfterSeconds > 300 || info.rateLimitType === "low") {
|
|
27
|
+
throw new figma_types_js_1.FigmaRateLimitError(`Figma API rate limited (retry-after: ${info.retryAfterSeconds}s)`, info);
|
|
28
|
+
}
|
|
29
|
+
if (attempt < maxAttempts) {
|
|
30
|
+
const delayMs = info.retryAfterSeconds * 1000;
|
|
31
|
+
onRetry?.(attempt, delayMs, `429 rate limited, retry-after ${info.retryAfterSeconds}s`);
|
|
32
|
+
await sleep(delayMs);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// All retries exhausted
|
|
37
|
+
throw new figma_types_js_1.FigmaRateLimitError(`Figma API rate limited after ${maxAttempts} attempts`, info ?? { retryAfterSeconds: 60 });
|
|
38
|
+
}
|
|
39
|
+
if (response.status >= 500 && attempt < maxAttempts) {
|
|
40
|
+
const delayMs = 1000 * Math.pow(2, attempt - 1); // 1s, 2s, 4s
|
|
41
|
+
onRetry?.(attempt, delayMs, `server error ${response.status}`);
|
|
42
|
+
await sleep(delayMs);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
// Success or non-retryable error
|
|
46
|
+
if (response.ok) {
|
|
47
|
+
rateLimiter.onSuccess();
|
|
48
|
+
}
|
|
49
|
+
return response;
|
|
50
|
+
}
|
|
51
|
+
// Should not reach here, but TypeScript needs it
|
|
52
|
+
throw new Error("figmaRetry: exhausted all attempts");
|
|
53
|
+
}
|
|
54
|
+
function sleep(ms) {
|
|
55
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=figma-retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-retry.js","sourceRoot":"","sources":["../../../src/figma/figma-retry.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAiBH,gCAuDC;AAtED,qDAA8E;AAS9E;;;;;GAKG;AACI,KAAK,UAAU,UAAU,CAC9B,EAA2B,EAC3B,OAA0B;IAE1B,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAE1D,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACxD,MAAM,WAAW,CAAC,OAAO,EAAE,CAAC;QAE5B,MAAM,QAAQ,GAAG,MAAM,EAAE,EAAE,CAAC;QAE5B,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAA,sCAAqB,EAAC,QAAQ,CAAC,CAAC;YAC7C,IAAI,IAAI,EAAE,CAAC;gBACT,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBAEhC,0DAA0D;gBAC1D,IAAI,IAAI,CAAC,iBAAiB,GAAG,GAAG,IAAI,IAAI,CAAC,aAAa,KAAK,KAAK,EAAE,CAAC;oBACjE,MAAM,IAAI,oCAAmB,CAC3B,wCAAwC,IAAI,CAAC,iBAAiB,IAAI,EAClE,IAAI,CACL,CAAC;gBACJ,CAAC;gBAED,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;oBAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;oBAC9C,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,iCAAiC,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;oBACxF,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;oBACrB,SAAS;gBACX,CAAC;YACH,CAAC;YAED,wBAAwB;YACxB,MAAM,IAAI,oCAAmB,CAC3B,gCAAgC,WAAW,WAAW,EACtD,IAAI,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAClC,CAAC;QACJ,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;YACpD,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa;YAC9D,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/D,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;YACrB,SAAS;QACX,CAAC;QAED,iCAAiC;QACjC,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,WAAW,CAAC,SAAS,EAAE,CAAC;QAC1B,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,iDAAiD;IACjD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -39,5 +39,5 @@ export interface FigmaLayoutNode {
|
|
|
39
39
|
* @param token FIGMA_TOKEN
|
|
40
40
|
* @returns Parsed FigmaLayoutNode tree
|
|
41
41
|
*/
|
|
42
|
-
export declare function fetchFigmaStructure(fileKey: string, nodeId: string, token: string): Promise<FigmaLayoutNode>;
|
|
42
|
+
export declare function fetchFigmaStructure(fileKey: string, nodeId: string, token: string, client?: import("./figma-client.js").FigmaClient): Promise<FigmaLayoutNode>;
|
|
43
43
|
//# sourceMappingURL=figma-structure.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figma-structure.d.ts","sourceRoot":"","sources":["../../../src/figma/figma-structure.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,UAAU,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC;IAC/C,qBAAqB,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,CAAC;IAClE,qBAAqB,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,CAAC;IAC7D,WAAW,EAAE,MAAM,CAAC;IAGpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IAGtB,mBAAmB,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAG7E,sBAAsB,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACjD,oBAAoB,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAE/C,yBAAyB;IACzB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAyCD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"figma-structure.d.ts","sourceRoot":"","sources":["../../../src/figma/figma-structure.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,UAAU,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC;IAC/C,qBAAqB,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,CAAC;IAClE,qBAAqB,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,CAAC;IAC7D,WAAW,EAAE,MAAM,CAAC;IAGpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IAGtB,mBAAmB,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAG7E,sBAAsB,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACjD,oBAAoB,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAE/C,yBAAyB;IACzB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAyCD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,WAAW,GAC/C,OAAO,CAAC,eAAe,CAAC,CAmD1B"}
|
|
@@ -46,7 +46,17 @@ function parseNode(raw) {
|
|
|
46
46
|
* @param token FIGMA_TOKEN
|
|
47
47
|
* @returns Parsed FigmaLayoutNode tree
|
|
48
48
|
*/
|
|
49
|
-
async function fetchFigmaStructure(fileKey, nodeId, token) {
|
|
49
|
+
async function fetchFigmaStructure(fileKey, nodeId, token, client) {
|
|
50
|
+
// Use FigmaClient path if provided — gets caching + rate limiting
|
|
51
|
+
if (client) {
|
|
52
|
+
const data = (await client.fetchStructure(fileKey, nodeId, token));
|
|
53
|
+
const nodeData = data.nodes?.[nodeId];
|
|
54
|
+
if (!nodeData?.document) {
|
|
55
|
+
throw new Error(`Node "${nodeId}" not found in Figma file "${fileKey}". Check the node ID.`);
|
|
56
|
+
}
|
|
57
|
+
return parseNode(nodeData.document);
|
|
58
|
+
}
|
|
59
|
+
// Legacy direct fetch path
|
|
50
60
|
const apiUrl = `https://api.figma.com/v1/files/${fileKey}/nodes?ids=${encodeURIComponent(nodeId)}`;
|
|
51
61
|
const controller = new AbortController();
|
|
52
62
|
const timeout = setTimeout(() => controller.abort(), 20000);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figma-structure.js","sourceRoot":"","sources":["../../../src/figma/figma-structure.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAkFH,
|
|
1
|
+
{"version":3,"file":"figma-structure.js","sourceRoot":"","sources":["../../../src/figma/figma-structure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types, error classes, and header parsers for the Figma API resilience layer.
|
|
3
|
+
*/
|
|
4
|
+
export interface FigmaClientConfig {
|
|
5
|
+
/** Disk cache directory. Default: ~/.devlens/cache */
|
|
6
|
+
cacheDir?: string;
|
|
7
|
+
/** Memory cache max size in bytes. Default: 50MB */
|
|
8
|
+
memoryCacheMaxBytes?: number;
|
|
9
|
+
/** Default metadata TTL in ms. Default: 24h */
|
|
10
|
+
metadataTtlMs?: number;
|
|
11
|
+
/** Default image buffer TTL in ms. Default: 24h */
|
|
12
|
+
imageTtlMs?: number;
|
|
13
|
+
/** Initial rate limit budget (requests per minute). Default: 10 */
|
|
14
|
+
rateLimitBudget?: number;
|
|
15
|
+
/** Max retry attempts on 429/5xx. Default: 3 */
|
|
16
|
+
maxRetries?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface FigmaRateLimitInfo {
|
|
19
|
+
retryAfterSeconds: number;
|
|
20
|
+
/** X-Figma-Plan-Tier header (e.g., "starter", "pro", "org", "enterprise") */
|
|
21
|
+
planTier?: string;
|
|
22
|
+
/** X-Figma-Rate-Limit-Type header ("low" = View/Collab seat, "high" = Full/Dev seat) */
|
|
23
|
+
rateLimitType?: string;
|
|
24
|
+
/** X-Figma-Upgrade-Link header */
|
|
25
|
+
upgradeLink?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare class FigmaRateLimitError extends Error {
|
|
28
|
+
readonly info: FigmaRateLimitInfo;
|
|
29
|
+
constructor(message: string, info: FigmaRateLimitInfo);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse 429 response headers into structured rate limit info.
|
|
33
|
+
* Returns null if the response is not a 429.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseRateLimitHeaders(response: Response): FigmaRateLimitInfo | null;
|
|
36
|
+
export interface RateLimiterStatus {
|
|
37
|
+
budget: number;
|
|
38
|
+
tokens: number;
|
|
39
|
+
pausedUntil: number;
|
|
40
|
+
detectedPlanTier?: string;
|
|
41
|
+
detectedSeatType?: string;
|
|
42
|
+
totalRequests: number;
|
|
43
|
+
throttledRequests: number;
|
|
44
|
+
isLimited: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface CacheStats {
|
|
47
|
+
memoryEntries: number;
|
|
48
|
+
diskEntries: number;
|
|
49
|
+
memoryBytes: number;
|
|
50
|
+
hitRate: number;
|
|
51
|
+
hits: number;
|
|
52
|
+
misses: number;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=figma-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-types.d.ts","sourceRoot":"","sources":["../../../src/figma/figma-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAG1B,IAAI,EAAE,kBAAkB;gBADxC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,kBAAkB;CAK3C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,QAAQ,GACjB,kBAAkB,GAAG,IAAI,CAY3B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared types, error classes, and header parsers for the Figma API resilience layer.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FigmaRateLimitError = void 0;
|
|
7
|
+
exports.parseRateLimitHeaders = parseRateLimitHeaders;
|
|
8
|
+
class FigmaRateLimitError extends Error {
|
|
9
|
+
info;
|
|
10
|
+
constructor(message, info) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.info = info;
|
|
13
|
+
this.name = "FigmaRateLimitError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.FigmaRateLimitError = FigmaRateLimitError;
|
|
17
|
+
/**
|
|
18
|
+
* Parse 429 response headers into structured rate limit info.
|
|
19
|
+
* Returns null if the response is not a 429.
|
|
20
|
+
*/
|
|
21
|
+
function parseRateLimitHeaders(response) {
|
|
22
|
+
if (response.status !== 429)
|
|
23
|
+
return null;
|
|
24
|
+
const retryAfter = response.headers.get("retry-after");
|
|
25
|
+
const retryAfterSeconds = retryAfter ? parseInt(retryAfter, 10) : 60;
|
|
26
|
+
return {
|
|
27
|
+
retryAfterSeconds: isNaN(retryAfterSeconds) ? 60 : retryAfterSeconds,
|
|
28
|
+
planTier: response.headers.get("x-figma-plan-tier") ?? undefined,
|
|
29
|
+
rateLimitType: response.headers.get("x-figma-rate-limit-type") ?? undefined,
|
|
30
|
+
upgradeLink: response.headers.get("x-figma-upgrade-link") ?? undefined,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=figma-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-types.js","sourceRoot":"","sources":["../../../src/figma/figma-types.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAyCH,sDAcC;AA5BD,MAAa,mBAAoB,SAAQ,KAAK;IAG1B;IAFlB,YACE,OAAe,EACC,IAAwB;QAExC,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,SAAI,GAAJ,IAAI,CAAoB;QAGxC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AARD,kDAQC;AAED;;;GAGG;AACH,SAAgB,qBAAqB,CACnC,QAAkB;IAElB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACvD,MAAM,iBAAiB,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAErE,OAAO;QACL,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB;QACpE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,SAAS;QAChE,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,IAAI,SAAS;QAC3E,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,SAAS;KACvE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type PrototypeUrlType = "figma-design" | "figma-proto" | "web";
|
|
2
|
+
export interface ParsedFigmaUrl {
|
|
3
|
+
fileKey: string;
|
|
4
|
+
nodeId?: string;
|
|
5
|
+
fileName?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ParsedPrototypeUrl {
|
|
8
|
+
type: PrototypeUrlType;
|
|
9
|
+
originalUrl: string;
|
|
10
|
+
fileKey?: string;
|
|
11
|
+
nodeId?: string;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Parse a Figma design URL (supports /design/, /branch/, and both
|
|
16
|
+
* dash-separated and colon-separated node IDs).
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseFigmaUrl(url: string): ParsedFigmaUrl | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Normalise a node ID to colon-separated format ("10-200" -> "10:200").
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeNodeId(nodeId: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Detect the prototype URL type and extract relevant identifiers.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parsePrototypeUrl(url: string): ParsedPrototypeUrl;
|
|
27
|
+
/**
|
|
28
|
+
* Convert a Figma file key (and optional starting node) to a
|
|
29
|
+
* public prototype URL.
|
|
30
|
+
*/
|
|
31
|
+
export declare function toPrototypeUrl(fileKey: string, startNodeId?: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Check whether a URL already points to a Figma prototype viewer.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isPrototypeUrl(url: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Normalise a web URL to its origin (scheme + host).
|
|
38
|
+
*/
|
|
39
|
+
export declare function discoverBaseUrl(url: string): string;
|
|
40
|
+
//# sourceMappingURL=url-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-parser.d.ts","sourceRoot":"","sources":["../../../src/figma/url-parser.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,aAAa,GAAG,KAAK,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAWD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,GACV,cAAc,GAAG,SAAS,CA6B5B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,CA0BjE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAOR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOnD"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseFigmaUrl = parseFigmaUrl;
|
|
4
|
+
exports.normalizeNodeId = normalizeNodeId;
|
|
5
|
+
exports.parsePrototypeUrl = parsePrototypeUrl;
|
|
6
|
+
exports.toPrototypeUrl = toPrototypeUrl;
|
|
7
|
+
exports.isPrototypeUrl = isPrototypeUrl;
|
|
8
|
+
exports.discoverBaseUrl = discoverBaseUrl;
|
|
9
|
+
const FIGMA_DESIGN_REGEX = /figma\.com\/design\/([^/]+)\/([^?/]*)\??(?:.*node-id=(\d+-\d+))?/;
|
|
10
|
+
const FIGMA_BRANCH_REGEX = /figma\.com\/design\/[^/]+\/branch\/([^/]+)\/([^?/]*)\??(?:.*node-id=(\d+-\d+))?/;
|
|
11
|
+
const FIGMA_PROTO_REGEX = /figma\.com\/proto\/([^/]+)\/([^?/]*)\??(?:.*node-id=(\d+-\d+))?/;
|
|
12
|
+
/**
|
|
13
|
+
* Parse a Figma design URL (supports /design/, /branch/, and both
|
|
14
|
+
* dash-separated and colon-separated node IDs).
|
|
15
|
+
*/
|
|
16
|
+
function parseFigmaUrl(url) {
|
|
17
|
+
const branchMatch = url.match(FIGMA_BRANCH_REGEX);
|
|
18
|
+
if (branchMatch) {
|
|
19
|
+
return {
|
|
20
|
+
fileKey: branchMatch[1],
|
|
21
|
+
nodeId: branchMatch[3]?.replace("-", ":"),
|
|
22
|
+
fileName: decodeURIComponent(branchMatch[2] || ""),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const designMatch = url.match(FIGMA_DESIGN_REGEX);
|
|
26
|
+
if (designMatch) {
|
|
27
|
+
return {
|
|
28
|
+
fileKey: designMatch[1],
|
|
29
|
+
nodeId: designMatch[3]?.replace("-", ":"),
|
|
30
|
+
fileName: decodeURIComponent(designMatch[2] || ""),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const protoMatch = url.match(FIGMA_PROTO_REGEX);
|
|
34
|
+
if (protoMatch) {
|
|
35
|
+
return {
|
|
36
|
+
fileKey: protoMatch[1],
|
|
37
|
+
nodeId: protoMatch[3]?.replace("-", ":"),
|
|
38
|
+
fileName: decodeURIComponent(protoMatch[2] || ""),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Normalise a node ID to colon-separated format ("10-200" -> "10:200").
|
|
45
|
+
*/
|
|
46
|
+
function normalizeNodeId(nodeId) {
|
|
47
|
+
return nodeId.replace("-", ":");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Detect the prototype URL type and extract relevant identifiers.
|
|
51
|
+
*/
|
|
52
|
+
function parsePrototypeUrl(url) {
|
|
53
|
+
if (FIGMA_PROTO_REGEX.test(url)) {
|
|
54
|
+
const parsed = parseFigmaUrl(url);
|
|
55
|
+
return {
|
|
56
|
+
type: "figma-proto",
|
|
57
|
+
originalUrl: url,
|
|
58
|
+
fileKey: parsed?.fileKey,
|
|
59
|
+
nodeId: parsed?.nodeId,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (FIGMA_DESIGN_REGEX.test(url) || FIGMA_BRANCH_REGEX.test(url)) {
|
|
63
|
+
const parsed = parseFigmaUrl(url);
|
|
64
|
+
return {
|
|
65
|
+
type: "figma-design",
|
|
66
|
+
originalUrl: url,
|
|
67
|
+
fileKey: parsed?.fileKey,
|
|
68
|
+
nodeId: parsed?.nodeId,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
type: "web",
|
|
73
|
+
originalUrl: url,
|
|
74
|
+
baseUrl: discoverBaseUrl(url),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Convert a Figma file key (and optional starting node) to a
|
|
79
|
+
* public prototype URL.
|
|
80
|
+
*/
|
|
81
|
+
function toPrototypeUrl(fileKey, startNodeId) {
|
|
82
|
+
let url = `https://www.figma.com/proto/${fileKey}/Prototype`;
|
|
83
|
+
if (startNodeId) {
|
|
84
|
+
const dashId = startNodeId.replace(":", "-");
|
|
85
|
+
url += `?node-id=${dashId}&starting-point-node-id=${dashId}`;
|
|
86
|
+
}
|
|
87
|
+
return url;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check whether a URL already points to a Figma prototype viewer.
|
|
91
|
+
*/
|
|
92
|
+
function isPrototypeUrl(url) {
|
|
93
|
+
return FIGMA_PROTO_REGEX.test(url);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Normalise a web URL to its origin (scheme + host).
|
|
97
|
+
*/
|
|
98
|
+
function discoverBaseUrl(url) {
|
|
99
|
+
try {
|
|
100
|
+
const u = new URL(url);
|
|
101
|
+
return u.origin;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return url;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=url-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-parser.js","sourceRoot":"","sources":["../../../src/figma/url-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,6 +23,11 @@ export declare class DeviceManager {
|
|
|
23
23
|
private checkDeviceHealth;
|
|
24
24
|
private discoverAndroidDevices;
|
|
25
25
|
private discoverIosDevices;
|
|
26
|
+
/**
|
|
27
|
+
* Get Device instances for multiple device IDs simultaneously.
|
|
28
|
+
* Used by multi-device tools for parallel operations.
|
|
29
|
+
*/
|
|
30
|
+
getMultipleDevices(deviceIds: string[]): Promise<Device[]>;
|
|
26
31
|
private getAdbPath;
|
|
27
32
|
}
|
|
28
33
|
//# sourceMappingURL=device-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-manager.d.ts","sourceRoot":"","sources":["../../../src/platform/device-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,aAAa,CAAC;AAMtD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,cAAc,CAAkC;IAElD,eAAe,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAkB9C,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqDnD;;;OAGG;YACW,iBAAiB;YAgCjB,sBAAsB;YAkDtB,kBAAkB;IAsChC,OAAO,CAAC,UAAU;CAQnB"}
|
|
1
|
+
{"version":3,"file":"device-manager.d.ts","sourceRoot":"","sources":["../../../src/platform/device-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,aAAa,CAAC;AAMtD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,cAAc,CAAkC;IAElD,eAAe,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAkB9C,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqDnD;;;OAGG;YACW,iBAAiB;YAgCjB,sBAAsB;YAkDtB,kBAAkB;IAsChC;;;OAGG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAkBhE,OAAO,CAAC,UAAU;CAQnB"}
|