figma-local 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Figma Patch
3
+ *
4
+ * Patches Figma Desktop to enable remote debugging.
5
+ * Newer Figma versions block --remote-debugging-port by default.
6
+ */
7
+
8
+ import { readFileSync, writeFileSync, accessSync, constants } from 'fs';
9
+ import { execSync } from 'child_process';
10
+ import {
11
+ getAsarPath as platformGetAsarPath,
12
+ getFigmaBinaryPath as platformGetFigmaBinaryPath,
13
+ getFigmaCommand as platformGetFigmaCommand
14
+ } from './platform.js';
15
+
16
+ // Fixed CDP port (figma-use has 9222 hardcoded)
17
+ const CDP_PORT = 9222;
18
+
19
+ /**
20
+ * Get the CDP port (always 9222 for figma-use compatibility)
21
+ */
22
+ export function getCdpPort() {
23
+ return CDP_PORT;
24
+ }
25
+
26
+ // The string that blocks remote debugging
27
+ const BLOCK_STRING = Buffer.from('removeSwitch("remote-debugging-port")');
28
+ // The patched string (changes "port" to "Xort" to disable the block)
29
+ const PATCH_STRING = Buffer.from('removeSwitch("remote-debugXing-port")');
30
+
31
+ /**
32
+ * Get the path to Figma's app.asar file
33
+ */
34
+ export function getAsarPath() {
35
+ return platformGetAsarPath();
36
+ }
37
+
38
+ /**
39
+ * Check if Figma is patched
40
+ * @returns {boolean|null} true=patched, false=not patched, null=can't determine
41
+ */
42
+ export function isPatched() {
43
+ const asarPath = getAsarPath();
44
+ if (!asarPath) return null;
45
+
46
+ try {
47
+ const content = readFileSync(asarPath);
48
+
49
+ if (content.includes(PATCH_STRING)) {
50
+ return true; // Already patched
51
+ }
52
+
53
+ if (content.includes(BLOCK_STRING)) {
54
+ return false; // Needs patching
55
+ }
56
+
57
+ return null; // Can't determine (maybe old Figma version)
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Check if we have write access to the Figma app.asar file
65
+ * @returns {boolean} true if we can write, false otherwise
66
+ */
67
+ export function canPatchFigma() {
68
+ const asarPath = getAsarPath();
69
+ if (!asarPath) return false;
70
+
71
+ try {
72
+ accessSync(asarPath, constants.W_OK);
73
+ return true;
74
+ } catch {
75
+ return false;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Patch Figma to enable remote debugging
81
+ * @returns {boolean} true if patched successfully
82
+ */
83
+ export function patchFigma() {
84
+ const asarPath = getAsarPath();
85
+ if (!asarPath) {
86
+ throw new Error('Cannot detect Figma installation path for this platform');
87
+ }
88
+
89
+ // Check write access first
90
+ if (!canPatchFigma()) {
91
+ if (process.platform === 'darwin') {
92
+ throw new Error('No write access to Figma. Grant Terminal "Full Disk Access" in System Settings → Privacy & Security');
93
+ } else {
94
+ throw new Error('No write access to Figma. Try running as administrator.');
95
+ }
96
+ }
97
+
98
+ const content = readFileSync(asarPath);
99
+ const blockIndex = content.indexOf(BLOCK_STRING);
100
+
101
+ if (blockIndex < 0) {
102
+ // Check if already patched
103
+ if (content.includes(PATCH_STRING)) {
104
+ return true; // Already patched
105
+ }
106
+ throw new Error('Could not find the string to patch. Figma version may be incompatible.');
107
+ }
108
+
109
+ // Apply patch
110
+ PATCH_STRING.copy(content, blockIndex);
111
+ writeFileSync(asarPath, content);
112
+
113
+ // On macOS, re-sign the app
114
+ if (process.platform === 'darwin') {
115
+ try {
116
+ execSync('codesign --force --deep --sign - /Applications/Figma.app', { stdio: 'ignore' });
117
+ } catch {
118
+ // Codesign might fail but patch might still work
119
+ }
120
+ }
121
+
122
+ return true;
123
+ }
124
+
125
+ /**
126
+ * Unpatch Figma to restore original state (re-enables remote debugging block)
127
+ * @returns {boolean} true if unpatched successfully
128
+ */
129
+ export function unpatchFigma() {
130
+ const asarPath = getAsarPath();
131
+ if (!asarPath) {
132
+ throw new Error('Cannot detect Figma installation path for this platform');
133
+ }
134
+
135
+ const content = readFileSync(asarPath);
136
+ const patchIndex = content.indexOf(PATCH_STRING);
137
+
138
+ if (patchIndex < 0) {
139
+ // Check if already unpatched (original state)
140
+ if (content.includes(BLOCK_STRING)) {
141
+ return true; // Already in original state
142
+ }
143
+ throw new Error('Could not find the patched string. Figma may not have been patched by this tool.');
144
+ }
145
+
146
+ // Restore original
147
+ BLOCK_STRING.copy(content, patchIndex);
148
+ writeFileSync(asarPath, content);
149
+
150
+ // On macOS, re-sign the app
151
+ if (process.platform === 'darwin') {
152
+ try {
153
+ execSync('codesign --force --deep --sign - /Applications/Figma.app', { stdio: 'ignore' });
154
+ } catch {
155
+ // Codesign might fail but unpatch might still work
156
+ }
157
+ }
158
+
159
+ return true;
160
+ }
161
+
162
+ /**
163
+ * Get the command to start Figma with remote debugging
164
+ */
165
+ export function getFigmaCommand(port = 9222) {
166
+ return platformGetFigmaCommand(port);
167
+ }
168
+
169
+ /**
170
+ * Get the path to Figma binary
171
+ */
172
+ export function getFigmaBinaryPath() {
173
+ return platformGetFigmaBinaryPath();
174
+ }
175
+
176
+ export default {
177
+ getAsarPath,
178
+ isPatched,
179
+ canPatchFigma,
180
+ patchFigma,
181
+ unpatchFigma,
182
+ getFigmaCommand,
183
+ getFigmaBinaryPath,
184
+ getCdpPort
185
+ };