framer-dalton 0.0.11 → 0.0.13

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/cli.js CHANGED
@@ -10,7 +10,7 @@ import { z } from 'zod';
10
10
  import { fileURLToPath } from 'url';
11
11
  import { createTRPCClient, httpLink } from '@trpc/client';
12
12
 
13
- /* @framer/ai CLI v0.0.11 */
13
+ /* @framer/ai CLI v0.0.13 */
14
14
  var __defProp = Object.defineProperty;
15
15
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
16
16
  function openUrl(url) {
@@ -134,11 +134,10 @@ function extractProjectId(input) {
134
134
  if (/^[a-zA-Z0-9]+$/.test(input)) {
135
135
  return input;
136
136
  }
137
- const match = input.match(/\/projects\/[^/]+--([a-zA-Z0-9]+)/);
138
- if (match) {
139
- return match[1];
140
- }
141
- const slugMatch = input.match(/^(?:.+--)?([a-zA-Z0-9]+)(?:-[a-zA-Z0-9]+)?$/);
137
+ const candidate = input.match(/\/projects\/([^/?#]+)/)?.[1] ?? input;
138
+ const slugMatch = candidate.match(
139
+ /^(?:.+--)?([a-zA-Z0-9]+)(?:-[a-zA-Z0-9]+)?$/
140
+ );
142
141
  if (slugMatch) {
143
142
  return slugMatch[1];
144
143
  }
@@ -204,6 +203,16 @@ __name(printError, "printError");
204
203
 
205
204
  // src/auth-callback.ts
206
205
  var TIMEOUT_MS = 3e5;
206
+ var codeMessages = {
207
+ "user.denied": "Authorization denied by user.",
208
+ "project.access_denied": "You don\u2019t have access to this project.",
209
+ "project.not_found": "Project not found. Check that the project ID is correct.",
210
+ "project.unauthorized": "Not logged in to Framer.",
211
+ "api_key.access_denied": "You don\u2019t have permission to create API keys for this project.",
212
+ "api_key.unauthorized": "Session expired.",
213
+ connection_error: "Could not connect to Framer.",
214
+ unknown: "Authorization failed."
215
+ };
207
216
  var themes = {
208
217
  dark: {
209
218
  pageBackground: "rgb(17, 17, 17)",
@@ -271,15 +280,6 @@ function successHtml(theme) {
271
280
  });
272
281
  }
273
282
  __name(successHtml, "successHtml");
274
- function deniedHtml(theme) {
275
- return htmlPage({
276
- title: "Framer \u2014 Authorization Denied",
277
- heading: "Authorization Denied",
278
- message: "Agent access was denied. You can close this tab.",
279
- theme
280
- });
281
- }
282
- __name(deniedHtml, "deniedHtml");
283
283
  function errorHtml(theme) {
284
284
  return htmlPage({
285
285
  title: "Framer \u2014 Authorization Failed",
@@ -289,27 +289,53 @@ function errorHtml(theme) {
289
289
  });
290
290
  }
291
291
  __name(errorHtml, "errorHtml");
292
+ function codeHtml(code, theme) {
293
+ const heading = code === "user.denied" ? "Authorization Denied" : "Authorization Failed";
294
+ return htmlPage({
295
+ title: `Framer \u2014 ${heading}`,
296
+ heading,
297
+ message: codeMessages[code],
298
+ theme
299
+ });
300
+ }
301
+ __name(codeHtml, "codeHtml");
292
302
  function parseTheme(value) {
293
303
  return value === "light" ? "light" : "dark";
294
304
  }
295
305
  __name(parseTheme, "parseTheme");
306
+ var validCodes = new Set(Object.keys(codeMessages));
307
+ function parseCode(value) {
308
+ if (value !== null && validCodes.has(value)) return value;
309
+ return null;
310
+ }
311
+ __name(parseCode, "parseCode");
296
312
  async function acquireKeyFromBrowser(projectId) {
297
313
  const state = crypto.randomBytes(16).toString("hex");
298
314
  return new Promise((resolve, reject) => {
299
- let pendingResult = null;
315
+ let settled = false;
316
+ let pendingApiKey = null;
317
+ function settle(fn) {
318
+ if (settled) return;
319
+ settled = true;
320
+ cleanup();
321
+ fn();
322
+ }
323
+ __name(settle, "settle");
300
324
  const server = http.createServer((req, res) => {
301
325
  const url = new URL(req.url ?? "/", `http://127.0.0.1`);
302
326
  if (url.pathname === "/done") {
303
327
  const theme2 = parseTheme(url.searchParams.get("theme"));
304
328
  res.writeHead(200, { "Content-Type": "text/html" });
305
- res.end(successHtml(theme2));
306
- if (pendingResult) {
307
- const { apiKey: apiKey2 } = pendingResult;
308
- pendingResult = null;
309
- cleanup();
310
- print("\u2713 Agent authorized");
311
- resolve(apiKey2);
312
- }
329
+ res.end(successHtml(theme2), () => {
330
+ if (pendingApiKey) {
331
+ const apiKey2 = pendingApiKey;
332
+ pendingApiKey = null;
333
+ settle(() => {
334
+ print("\u2713 Agent authorized");
335
+ resolve(apiKey2);
336
+ });
337
+ }
338
+ });
313
339
  return;
314
340
  }
315
341
  if (url.pathname === "/error") {
@@ -324,12 +350,14 @@ async function acquireKeyFromBrowser(projectId) {
324
350
  return;
325
351
  }
326
352
  const theme = parseTheme(url.searchParams.get("theme"));
327
- const error = url.searchParams.get("error");
328
- if (error === "denied") {
353
+ const legacyError = url.searchParams.get("error");
354
+ const legacyCode = legacyError === "denied" ? "user.denied" : legacyError === "failed" ? "project.unauthorized" : null;
355
+ const code = parseCode(url.searchParams.get("code")) ?? legacyCode;
356
+ if (code !== null) {
329
357
  res.writeHead(200, { "Content-Type": "text/html" });
330
- res.end(deniedHtml(theme));
331
- cleanup();
332
- reject(new Error("Authorization denied by user."));
358
+ res.end(codeHtml(code, theme), () => {
359
+ settle(() => reject(new Error(codeMessages[code])));
360
+ });
333
361
  return;
334
362
  }
335
363
  const apiKey = url.searchParams.get("apiKey");
@@ -339,7 +367,7 @@ async function acquireKeyFromBrowser(projectId) {
339
367
  res.end();
340
368
  return;
341
369
  }
342
- pendingResult = { apiKey, theme };
370
+ pendingApiKey = apiKey;
343
371
  res.writeHead(302, { Location: `/done?theme=${theme}` });
344
372
  res.end();
345
373
  });
@@ -347,9 +375,10 @@ async function acquireKeyFromBrowser(projectId) {
347
375
  const pollTimer = setInterval(() => {
348
376
  const apiKey = getApiKey(projectId);
349
377
  if (apiKey) {
350
- cleanup();
351
- print("\u2713 API key detected from config");
352
- resolve(apiKey);
378
+ settle(() => {
379
+ print("\u2713 API key detected from config");
380
+ resolve(apiKey);
381
+ });
353
382
  }
354
383
  }, POLL_INTERVAL_MS);
355
384
  const HINT_MS = 55e3;
@@ -366,25 +395,31 @@ async function acquireKeyFromBrowser(projectId) {
366
395
  print("Waiting for authorization in browser...");
367
396
  }, HINT_MS);
368
397
  const timer = setTimeout(() => {
369
- cleanup();
370
- reject(
371
- new Error(
372
- "Browser authorization timed out. Use `framer project auth <projectUrlOrId> <apiKey>` instead."
398
+ settle(
399
+ () => reject(
400
+ new Error(
401
+ "Browser authorization timed out. Use `framer project auth <projectUrlOrId> <apiKey>` instead."
402
+ )
373
403
  )
374
404
  );
375
405
  }, TIMEOUT_MS);
406
+ let cleaned = false;
376
407
  function cleanup() {
408
+ if (cleaned) return;
409
+ cleaned = true;
377
410
  clearTimeout(timer);
378
411
  clearTimeout(hintTimer);
379
412
  clearInterval(pollTimer);
380
413
  server.close();
414
+ server.closeAllConnections();
381
415
  }
382
416
  __name(cleanup, "cleanup");
383
- server.listen(0, "127.0.0.1", async () => {
417
+ server.keepAliveTimeout = 0;
418
+ server.unref();
419
+ server.listen(0, "127.0.0.1", () => {
384
420
  const addr = server.address();
385
421
  if (!addr || typeof addr === "string") {
386
- cleanup();
387
- reject(new Error("Failed to start callback server."));
422
+ settle(() => reject(new Error("Failed to start callback server.")));
388
423
  return;
389
424
  }
390
425
  const callbackUrl = `http://127.0.0.1:${addr.port}/callback`;
@@ -393,13 +428,14 @@ async function acquireKeyFromBrowser(projectId) {
393
428
  deeplink.searchParams.set("state", state);
394
429
  deeplink.searchParams.set("projectId", projectId);
395
430
  const deeplinkStr = deeplink.toString();
396
- const opened = await openUrl(deeplinkStr);
397
- if (opened) {
398
- print("Waiting for authorization in browser...");
399
- } else {
400
- printError("Could not open browser. Open this URL manually:");
401
- printError(deeplinkStr);
402
- }
431
+ openUrl(deeplinkStr).then((opened) => {
432
+ if (opened) {
433
+ print("Waiting for authorization in browser...");
434
+ } else {
435
+ printError("Could not open browser. Open this URL manually:");
436
+ printError(deeplinkStr);
437
+ }
438
+ });
403
439
  });
404
440
  });
405
441
  }
@@ -14910,7 +14946,7 @@ ${typeDef}`);
14910
14946
  __name(renderDocs, "renderDocs");
14911
14947
  var __filename$1 = fileURLToPath(import.meta.url);
14912
14948
  var __dirname$1 = path4.dirname(__filename$1);
14913
- var VERSION = "0.0.11" ;
14949
+ var VERSION = "0.0.13" ;
14914
14950
  var RELAY_PORT = Number(process.env.FRAMER_CLI_PORT) || 19988;
14915
14951
  var client = createTRPCClient({
14916
14952
  links: [
@@ -13,7 +13,7 @@ import { createRequire } from 'module';
13
13
  import * as vm from 'vm';
14
14
  import { connect } from 'framer-api';
15
15
 
16
- /* @framer/ai relay server v0.0.11 */
16
+ /* @framer/ai relay server v0.0.13 */
17
17
  var __defProp = Object.defineProperty;
18
18
  var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
19
19
  var __typeError = (msg) => {
@@ -91,7 +91,7 @@ function log(message) {
91
91
  __name(log, "log");
92
92
  var __filename$1 = fileURLToPath(import.meta.url);
93
93
  path.dirname(__filename$1);
94
- var VERSION = "0.0.11" ;
94
+ var VERSION = "0.0.13" ;
95
95
  var RELAY_PORT = Number(process.env.FRAMER_CLI_PORT) || 19988;
96
96
  createTRPCClient({
97
97
  links: [
@@ -796,6 +796,7 @@ var appRouter = t.router({
796
796
  error: "Failed to get connection for session"
797
797
  };
798
798
  }
799
+ const start = performance.now();
799
800
  const result = await executeWithReconnect(
800
801
  session,
801
802
  framer,
@@ -804,8 +805,11 @@ var appRouter = t.router({
804
805
  () => sessionManager.reconnect(session),
805
806
  execId
806
807
  );
808
+ const elapsed = (performance.now() - start).toFixed(0);
807
809
  if (result.error) {
808
- log(`exec.error ${tag} error="${result.error}"`);
810
+ log(`exec.error ${tag} ${elapsed}ms error="${result.error}"`);
811
+ } else {
812
+ log(`exec.done ${tag} ${elapsed}ms`);
809
813
  }
810
814
  return result;
811
815
  } catch (_) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framer-dalton",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "framer-dalton": "./dist/cli.js"