faux-studio 0.4.3 → 0.4.5

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.
Files changed (2) hide show
  1. package/dist/index.js +58 -36
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10483,23 +10483,34 @@ var FileCredentialStore = class {
10483
10483
  var KeychainCredentialStore = class {
10484
10484
  name = "keychain";
10485
10485
  entry;
10486
+ cached = void 0;
10486
10487
  constructor(entry) {
10487
10488
  this.entry = entry;
10488
10489
  }
10489
10490
  async load() {
10491
+ if (this.cached !== void 0) return this.cached;
10490
10492
  try {
10491
10493
  const raw = await this.entry.getPassword();
10492
- if (!raw) return null;
10494
+ if (!raw) {
10495
+ this.cached = null;
10496
+ return null;
10497
+ }
10493
10498
  const creds = JSON.parse(raw);
10494
- if (!creds.jwt || !creds.refreshToken || !creds.user) return null;
10499
+ if (!creds.jwt || !creds.refreshToken || !creds.user) {
10500
+ this.cached = null;
10501
+ return null;
10502
+ }
10503
+ this.cached = creds;
10495
10504
  return creds;
10496
10505
  } catch {
10506
+ this.cached = null;
10497
10507
  return null;
10498
10508
  }
10499
10509
  }
10500
10510
  async save(creds) {
10501
10511
  try {
10502
10512
  await this.entry.setPassword(JSON.stringify(creds));
10513
+ this.cached = creds;
10503
10514
  } catch (err) {
10504
10515
  warn(`Could not save to keychain: ${err instanceof Error ? err.message : err}`);
10505
10516
  }
@@ -10507,6 +10518,7 @@ var KeychainCredentialStore = class {
10507
10518
  async clear() {
10508
10519
  try {
10509
10520
  await this.entry.deletePassword();
10521
+ this.cached = null;
10510
10522
  } catch {
10511
10523
  }
10512
10524
  }
@@ -10777,8 +10789,8 @@ function sanitizeSchema(obj) {
10777
10789
  }
10778
10790
  return result;
10779
10791
  }
10780
- function sanitizeTools(tools) {
10781
- return tools.map((t) => ({
10792
+ function sanitizeTools(tools2) {
10793
+ return tools2.map((t) => ({
10782
10794
  ...t,
10783
10795
  inputSchema: sanitizeSchema(t.inputSchema)
10784
10796
  }));
@@ -10801,10 +10813,10 @@ async function fetchRemoteTools(jwt2) {
10801
10813
  }
10802
10814
  async function getTools(jwt2) {
10803
10815
  try {
10804
- const tools = await fetchRemoteTools(jwt2);
10805
- await saveCachedTools({ tools, fetchedAt: Date.now() });
10806
- log(`${tools.length} tools loaded`);
10807
- return tools;
10816
+ const tools2 = await fetchRemoteTools(jwt2);
10817
+ await saveCachedTools({ tools: tools2, fetchedAt: Date.now() });
10818
+ log(`${tools2.length} tools loaded`);
10819
+ return tools2;
10808
10820
  } catch (fetchErr) {
10809
10821
  const cached2 = await loadCachedTools();
10810
10822
  if (cached2 && cached2.tools.length > 0) {
@@ -25937,7 +25949,7 @@ Resources provide quick read-only access to Figma state without tool calls:
25937
25949
  - Create components for reusable UI patterns.`;
25938
25950
  function createMcpServer(deps) {
25939
25951
  const server2 = new Server(
25940
- { name: "faux-studio", version: "0.4.3" },
25952
+ { name: "faux-studio", version: "0.4.5" },
25941
25953
  {
25942
25954
  capabilities: { tools: { listChanged: true }, resources: {}, logging: {} },
25943
25955
  instructions: INSTRUCTIONS
@@ -25960,7 +25972,7 @@ function createMcpServer(deps) {
25960
25972
  }
25961
25973
  }
25962
25974
  ];
25963
- const allTools = [...localTools, ...deps.getTools()].map(annotate);
25975
+ const allTools = [...localTools, ...await deps.getTools()].map(annotate);
25964
25976
  return { tools: allTools };
25965
25977
  });
25966
25978
  server2.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -26153,10 +26165,27 @@ async function startServer(server2) {
26153
26165
 
26154
26166
  // src/index.ts
26155
26167
  var auth;
26168
+ var tools = [];
26156
26169
  var cdpClient = null;
26157
26170
  var fileTracker = null;
26158
26171
  var pluginServer = new PluginWsServer();
26159
26172
  var forceTransport = process.env.FAUX_TRANSPORT;
26173
+ var initPromise2 = null;
26174
+ function lazyInit() {
26175
+ if (!initPromise2) {
26176
+ initPromise2 = doInit();
26177
+ }
26178
+ return initPromise2;
26179
+ }
26180
+ async function doInit() {
26181
+ auth = await ensureAuth();
26182
+ try {
26183
+ tools = await getTools(auth.jwt);
26184
+ } catch (err) {
26185
+ error(err instanceof Error ? err.message : String(err));
26186
+ process.exit(1);
26187
+ }
26188
+ }
26160
26189
  async function tryConnectCdp() {
26161
26190
  try {
26162
26191
  if (cdpClient?.connected && cdpClient.hasContext) return cdpClient;
@@ -26242,6 +26271,7 @@ async function recoverCdp(client, script) {
26242
26271
  }
26243
26272
  }
26244
26273
  async function generateWithAuth(toolName, params) {
26274
+ await lazyInit();
26245
26275
  auth = await refreshIfNeeded(auth);
26246
26276
  let result;
26247
26277
  try {
@@ -26390,13 +26420,7 @@ Call setup_figma again once the plugin shows "Ready".`,
26390
26420
  };
26391
26421
  }
26392
26422
  async function main() {
26393
- log(`faux-studio v${"0.4.3"}`);
26394
- try {
26395
- auth = await ensureAuth();
26396
- } catch (err) {
26397
- error(err instanceof Error ? err.message : String(err));
26398
- process.exit(1);
26399
- }
26423
+ log(`faux-studio v${"0.4.5"}`);
26400
26424
  try {
26401
26425
  const port = await pluginServer.start();
26402
26426
  if (forceTransport === "plugin") {
@@ -26409,25 +26433,16 @@ async function main() {
26409
26433
  } catch (err) {
26410
26434
  warn(`Plugin WS server failed to start: ${err instanceof Error ? err.message : err}`);
26411
26435
  }
26412
- let tools;
26413
- try {
26414
- tools = await getTools(auth.jwt);
26415
- } catch (err) {
26416
- error(err instanceof Error ? err.message : String(err));
26417
- process.exit(1);
26418
- }
26419
- if (forceTransport !== "plugin") {
26420
- try {
26421
- await tryConnectCdp();
26422
- } catch {
26423
- }
26424
- }
26425
26436
  const server2 = createMcpServer({
26426
- getTools: () => tools,
26437
+ getTools: async () => {
26438
+ await lazyInit();
26439
+ return tools;
26440
+ },
26427
26441
  generateScript: generateWithAuth,
26428
26442
  executeScript,
26429
26443
  getJwt: () => auth.jwt,
26430
26444
  refreshJwt: async (force) => {
26445
+ await lazyInit();
26431
26446
  auth = await refreshIfNeeded(auth, force);
26432
26447
  return auth.jwt;
26433
26448
  },
@@ -26442,11 +26457,11 @@ async function main() {
26442
26457
  return { userId: auth.user.id, handle: auth.user.handle, email: auth.user.email };
26443
26458
  },
26444
26459
  getAuthStatus: () => ({
26445
- userId: auth.user.id,
26446
- handle: auth.user.handle,
26447
- email: auth.user.email,
26448
- source: auth.source,
26449
- isApiKey: auth.source === "api-key"
26460
+ userId: auth?.user?.id ?? "",
26461
+ handle: auth?.user?.handle ?? "",
26462
+ email: auth?.user?.email ?? "",
26463
+ source: auth?.source ?? "none",
26464
+ isApiKey: auth?.source === "api-key"
26450
26465
  }),
26451
26466
  getTransport: () => {
26452
26467
  if (pluginServer.hasConnections) return "plugin";
@@ -26457,8 +26472,15 @@ async function main() {
26457
26472
  });
26458
26473
  await startServer(server2);
26459
26474
  setServer(server2);
26475
+ if (forceTransport !== "plugin") {
26476
+ try {
26477
+ await tryConnectCdp();
26478
+ } catch {
26479
+ }
26480
+ }
26460
26481
  const REFRESH_INTERVAL = 30 * 6e4;
26461
26482
  setInterval(async () => {
26483
+ if (!initPromise2) return;
26462
26484
  try {
26463
26485
  auth = await refreshIfNeeded(auth);
26464
26486
  const fresh = await getTools(auth.jwt);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "faux-studio",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "AI-powered Figma design via MCP — connect any AI client to Figma Desktop",
5
5
  "type": "module",
6
6
  "bin": {