framer-code-link 0.4.0 → 0.4.1
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/index.mjs +155 -115
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -178,7 +178,9 @@ function debug(message, ...args) {
|
|
|
178
178
|
function info(message, ...args) {
|
|
179
179
|
if (currentLevel <= LogLevel.INFO) {
|
|
180
180
|
const formatted = args.length > 0 ? `${message} ${args.join(" ")}` : message;
|
|
181
|
-
logWithDedupe(formatted, () =>
|
|
181
|
+
logWithDedupe(formatted, () => {
|
|
182
|
+
console.log(formatted);
|
|
183
|
+
});
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
/**
|
|
@@ -217,19 +219,25 @@ function success(message, ...args) {
|
|
|
217
219
|
function fileDown(fileName) {
|
|
218
220
|
if (currentLevel <= LogLevel.INFO) {
|
|
219
221
|
const msg = ` ${import_picocolors.default.blue("↓")} ${fileName}`;
|
|
220
|
-
logWithDedupe(msg, () =>
|
|
222
|
+
logWithDedupe(msg, () => {
|
|
223
|
+
console.log(msg);
|
|
224
|
+
});
|
|
221
225
|
}
|
|
222
226
|
}
|
|
223
227
|
function fileUp(fileName) {
|
|
224
228
|
if (currentLevel <= LogLevel.INFO) {
|
|
225
229
|
const msg = ` ${import_picocolors.default.green("↑")} ${fileName}`;
|
|
226
|
-
logWithDedupe(msg, () =>
|
|
230
|
+
logWithDedupe(msg, () => {
|
|
231
|
+
console.log(msg);
|
|
232
|
+
});
|
|
227
233
|
}
|
|
228
234
|
}
|
|
229
235
|
function fileDelete(fileName) {
|
|
230
236
|
if (currentLevel <= LogLevel.INFO) {
|
|
231
237
|
const msg = ` ${import_picocolors.default.red("×")} ${fileName}`;
|
|
232
|
-
logWithDedupe(msg, () =>
|
|
238
|
+
logWithDedupe(msg, () => {
|
|
239
|
+
console.log(msg);
|
|
240
|
+
});
|
|
233
241
|
}
|
|
234
242
|
}
|
|
235
243
|
/**
|
|
@@ -341,7 +349,7 @@ function initConnection(port) {
|
|
|
341
349
|
}
|
|
342
350
|
});
|
|
343
351
|
ws.on("close", (code, reason) => {
|
|
344
|
-
debug(`Client disconnected (code: ${code}, reason: ${reason
|
|
352
|
+
debug(`Client disconnected (code: ${code}, reason: ${reason.toString()})`);
|
|
345
353
|
handlers.onDisconnect?.();
|
|
346
354
|
});
|
|
347
355
|
ws.on("error", (err) => {
|
|
@@ -350,10 +358,20 @@ function initConnection(port) {
|
|
|
350
358
|
});
|
|
351
359
|
resolve({
|
|
352
360
|
on(event, handler) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
361
|
+
switch (event) {
|
|
362
|
+
case "handshake":
|
|
363
|
+
handlers.onHandshake = handler;
|
|
364
|
+
break;
|
|
365
|
+
case "message":
|
|
366
|
+
handlers.onMessage = handler;
|
|
367
|
+
break;
|
|
368
|
+
case "disconnect":
|
|
369
|
+
handlers.onDisconnect = handler;
|
|
370
|
+
break;
|
|
371
|
+
case "error":
|
|
372
|
+
handlers.onError = handler;
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
357
375
|
},
|
|
358
376
|
close() {
|
|
359
377
|
wss.close();
|
|
@@ -449,7 +467,7 @@ function normalizePath$1(filePath) {
|
|
|
449
467
|
function initWatcher(filesDir) {
|
|
450
468
|
const handlers = [];
|
|
451
469
|
const watcher = chokidar.watch(filesDir, {
|
|
452
|
-
ignored: /(^|[
|
|
470
|
+
ignored: /(^|[/\\])\.\./,
|
|
453
471
|
persistent: true,
|
|
454
472
|
ignoreInitial: false
|
|
455
473
|
});
|
|
@@ -485,12 +503,18 @@ function initWatcher(filesDir) {
|
|
|
485
503
|
debug(`Watcher event: ${kind} ${relativePath}`);
|
|
486
504
|
for (const handler of handlers) handler(event);
|
|
487
505
|
};
|
|
488
|
-
watcher.on("add", (filePath) =>
|
|
489
|
-
|
|
490
|
-
|
|
506
|
+
watcher.on("add", (filePath) => {
|
|
507
|
+
emitEvent("add", filePath);
|
|
508
|
+
});
|
|
509
|
+
watcher.on("change", (filePath) => {
|
|
510
|
+
emitEvent("change", filePath);
|
|
511
|
+
});
|
|
512
|
+
watcher.on("unlink", (filePath) => {
|
|
513
|
+
emitEvent("delete", filePath);
|
|
514
|
+
});
|
|
491
515
|
return {
|
|
492
|
-
on(
|
|
493
|
-
|
|
516
|
+
on(_event, handler) {
|
|
517
|
+
handlers.push(handler);
|
|
494
518
|
},
|
|
495
519
|
async close() {
|
|
496
520
|
await watcher.close();
|
|
@@ -643,7 +667,7 @@ async function detectConflicts(remoteFiles, filesDir, options = {}) {
|
|
|
643
667
|
const preferRemote = options.preferRemote ?? false;
|
|
644
668
|
const persistedState = options.persistedState;
|
|
645
669
|
const getPersistedState = (fileName) => persistedState?.get(normalizeForComparison(fileName)) ?? persistedState?.get(fileName);
|
|
646
|
-
debug(`Detecting conflicts for ${remoteFiles.length} remote files`);
|
|
670
|
+
debug(`Detecting conflicts for ${String(remoteFiles.length)} remote files`);
|
|
647
671
|
const localFiles = await listFiles(filesDir);
|
|
648
672
|
const localFileMap = new Map(localFiles.map((f) => [normalizeForComparison(f.name), f]));
|
|
649
673
|
const remoteFileMap = new Map(remoteFiles.map((f) => {
|
|
@@ -666,7 +690,7 @@ async function detectConflicts(remoteFiles, filesDir, options = {}) {
|
|
|
666
690
|
localContent: null,
|
|
667
691
|
remoteContent: remote.content,
|
|
668
692
|
remoteModifiedAt: remote.modifiedAt,
|
|
669
|
-
lastSyncedAt: persisted
|
|
693
|
+
lastSyncedAt: persisted.timestamp
|
|
670
694
|
});
|
|
671
695
|
} else writes.push({
|
|
672
696
|
name: normalized.relativePath,
|
|
@@ -708,13 +732,13 @@ async function detectConflicts(remoteFiles, filesDir, options = {}) {
|
|
|
708
732
|
const persisted = getPersistedState(local.name);
|
|
709
733
|
if (persisted) {
|
|
710
734
|
const localClean = hashFileContent(local.content) === persisted.contentHash;
|
|
711
|
-
debug(`Conflict: ${local.name} deleted in Framer (localClean=${localClean})`);
|
|
735
|
+
debug(`Conflict: ${local.name} deleted in Framer (localClean=${String(localClean)})`);
|
|
712
736
|
conflicts.push({
|
|
713
737
|
fileName: local.name,
|
|
714
738
|
localContent: local.content,
|
|
715
739
|
remoteContent: null,
|
|
716
740
|
localModifiedAt: local.modifiedAt,
|
|
717
|
-
lastSyncedAt: persisted
|
|
741
|
+
lastSyncedAt: persisted.timestamp,
|
|
718
742
|
localClean
|
|
719
743
|
});
|
|
720
744
|
} else localOnly.push({
|
|
@@ -818,7 +842,7 @@ async function deleteLocalFile(fileName, filesDir, hashTracker) {
|
|
|
818
842
|
hashTracker.forget(normalized.relativePath);
|
|
819
843
|
debug(`Deleted file: ${normalized.relativePath}`);
|
|
820
844
|
} catch (err) {
|
|
821
|
-
if (err
|
|
845
|
+
if (err.code === "ENOENT") {
|
|
822
846
|
hashTracker.forget(normalized.relativePath);
|
|
823
847
|
debug(`File already deleted: ${normalized.relativePath}`);
|
|
824
848
|
return;
|
|
@@ -844,7 +868,6 @@ async function readFileSafe(fileName, filesDir) {
|
|
|
844
868
|
*/
|
|
845
869
|
function filterEchoedFiles(files, hashTracker) {
|
|
846
870
|
return files.filter((file) => {
|
|
847
|
-
if (file.content === void 0) return true;
|
|
848
871
|
return !hashTracker.shouldSkip(file.name, file.content);
|
|
849
872
|
});
|
|
850
873
|
}
|
|
@@ -878,7 +901,7 @@ function isSupportedExtension$1(fileName) {
|
|
|
878
901
|
function extractImports(code) {
|
|
879
902
|
const imports = [];
|
|
880
903
|
const seen = /* @__PURE__ */ new Set();
|
|
881
|
-
const npmRegex = /import\s+(?:(?:\*\s+as\s+\w+)|(?:\w+)|(?:\{[^}]*\}))\s+from\s+['"]([
|
|
904
|
+
const npmRegex = /import\s+(?:(?:\*\s+as\s+\w+)|(?:\w+)|(?:\{[^}]*\}))\s+from\s+['"]([^./][^'"]+)['"]/g;
|
|
882
905
|
const urlRegex = /import\s+(?:(?:\*\s+as\s+\w+)|(?:\w+)|(?:\{[^}]*\}))\s+from\s+['"]https?:\/\/[^'"]+['"]/g;
|
|
883
906
|
let match;
|
|
884
907
|
while ((match = npmRegex.exec(code)) !== null) {
|
|
@@ -910,7 +933,7 @@ function extractImports(code) {
|
|
|
910
933
|
* Attempt to derive an npm-style package specifier from a URL import.
|
|
911
934
|
*/
|
|
912
935
|
function extractPackageFromUrl(url) {
|
|
913
|
-
return
|
|
936
|
+
return /\/(@?[^@/]+(?:\/[^@/]+)?)/.exec(url)?.[1] ?? null;
|
|
914
937
|
}
|
|
915
938
|
|
|
916
939
|
//#endregion
|
|
@@ -963,29 +986,31 @@ var Installer = class {
|
|
|
963
986
|
},
|
|
964
987
|
progress: () => {},
|
|
965
988
|
finished: (files) => {
|
|
966
|
-
if (files
|
|
989
|
+
if (files.size > 0) debug("ATA: type acquisition complete");
|
|
967
990
|
},
|
|
968
991
|
errorMessage: (message, error$1) => {
|
|
969
992
|
warn(`ATA warning: ${message}`, error$1);
|
|
970
993
|
},
|
|
971
|
-
receivedFile:
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
if (
|
|
978
|
-
seenPackages.
|
|
979
|
-
|
|
994
|
+
receivedFile: (code, receivedPath) => {
|
|
995
|
+
(async () => {
|
|
996
|
+
const normalized = receivedPath.replace(/^\//, "");
|
|
997
|
+
const destination = path.join(this.projectDir, normalized);
|
|
998
|
+
const pkgMatch = /\/node_modules\/(@?[^/]+(?:\/[^/]+)?)\//.exec(receivedPath);
|
|
999
|
+
try {
|
|
1000
|
+
if (await fs.readFile(destination, "utf-8") === code) {
|
|
1001
|
+
if (pkgMatch && !seenPackages.has(pkgMatch[1])) {
|
|
1002
|
+
seenPackages.add(pkgMatch[1]);
|
|
1003
|
+
debug(`📦 Types: ${pkgMatch[1]} (from disk cache)`);
|
|
1004
|
+
}
|
|
1005
|
+
return;
|
|
980
1006
|
}
|
|
981
|
-
|
|
1007
|
+
} catch {}
|
|
1008
|
+
if (pkgMatch && !seenPackages.has(pkgMatch[1])) {
|
|
1009
|
+
seenPackages.add(pkgMatch[1]);
|
|
1010
|
+
debug(`📦 Types: ${pkgMatch[1]}`);
|
|
982
1011
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
seenPackages.add(pkgMatch[1]);
|
|
986
|
-
debug(`📦 Types: ${pkgMatch[1]}`);
|
|
987
|
-
}
|
|
988
|
-
await this.writeTypeFile(receivedPath, code);
|
|
1012
|
+
await this.writeTypeFile(receivedPath, code);
|
|
1013
|
+
})();
|
|
989
1014
|
}
|
|
990
1015
|
}
|
|
991
1016
|
});
|
|
@@ -1073,11 +1098,11 @@ var Installer = class {
|
|
|
1073
1098
|
warn(`Failed to write type file ${destination}`, err);
|
|
1074
1099
|
return;
|
|
1075
1100
|
}
|
|
1076
|
-
if (
|
|
1101
|
+
if (/node_modules\/@types\/[^/]+\/index\.d\.ts$/.exec(normalized)) await this.ensureTypesPackageJson(normalized);
|
|
1077
1102
|
if (normalized.includes("node_modules/@types/react/index.d.ts")) await this.patchReactTypes(destination);
|
|
1078
1103
|
}
|
|
1079
1104
|
async ensureTypesPackageJson(normalizedPath) {
|
|
1080
|
-
const pkgMatch =
|
|
1105
|
+
const pkgMatch = /node_modules\/(@types\/[^/]+)\//.exec(normalizedPath);
|
|
1081
1106
|
if (!pkgMatch) return;
|
|
1082
1107
|
const pkgName = pkgMatch[1];
|
|
1083
1108
|
const pkgDir = path.join(this.projectDir, "node_modules", pkgName);
|
|
@@ -1089,16 +1114,7 @@ var Installer = class {
|
|
|
1089
1114
|
const version$1 = npmData["dist-tags"]?.latest;
|
|
1090
1115
|
if (!version$1 || !npmData.versions?.[version$1]) return;
|
|
1091
1116
|
const pkg = npmData.versions[version$1];
|
|
1092
|
-
if (pkg.exports
|
|
1093
|
-
const fixExport = (value) => {
|
|
1094
|
-
if (typeof value === "string") return { types: value.replace(/\.js$/, ".d.ts").replace(/\.cjs$/, ".d.cts") };
|
|
1095
|
-
if (value && typeof value === "object") {
|
|
1096
|
-
if ((value.import || value.require) && !value.types) value.types = (value.import || value.require).replace(/\.js$/, ".d.ts").replace(/\.cjs$/, ".d.cts");
|
|
1097
|
-
}
|
|
1098
|
-
return value;
|
|
1099
|
-
};
|
|
1100
|
-
for (const key of Object.keys(pkg.exports)) pkg.exports[key] = fixExport(pkg.exports[key]);
|
|
1101
|
-
}
|
|
1117
|
+
if (pkg.exports) for (const key of Object.keys(pkg.exports)) pkg.exports[key] = fixExportTypes(pkg.exports[key]);
|
|
1102
1118
|
await fs.mkdir(pkgDir, { recursive: true });
|
|
1103
1119
|
await fs.writeFile(pkgJsonPath, JSON.stringify(pkg, null, 2));
|
|
1104
1120
|
} catch {}
|
|
@@ -1108,7 +1124,7 @@ var Installer = class {
|
|
|
1108
1124
|
let content = await fs.readFile(destination, "utf-8");
|
|
1109
1125
|
if (content.includes("function useRef<T = undefined>()")) return;
|
|
1110
1126
|
const overloadPattern = /function useRef<T>\(initialValue: T \| undefined\): RefObject<T \| undefined>;/;
|
|
1111
|
-
if (!
|
|
1127
|
+
if (!content.includes("function useRef<T>(initialValue: T | undefined)")) return;
|
|
1112
1128
|
content = content.replace(overloadPattern, `function useRef<T>(initialValue: T | undefined): RefObject<T | undefined>;
|
|
1113
1129
|
function useRef<T = undefined>(): MutableRefObject<T | undefined>;`);
|
|
1114
1130
|
await fs.writeFile(destination, content, "utf-8");
|
|
@@ -1248,11 +1264,24 @@ declare module "*.json"
|
|
|
1248
1264
|
}));
|
|
1249
1265
|
}
|
|
1250
1266
|
};
|
|
1267
|
+
/**
|
|
1268
|
+
* Transform package.json exports to include .d.ts type paths
|
|
1269
|
+
*/
|
|
1270
|
+
function fixExportTypes(value) {
|
|
1271
|
+
if (typeof value === "string") return { types: value.replace(/\.js$/, ".d.ts").replace(/\.cjs$/, ".d.cts") };
|
|
1272
|
+
if ((value.import ?? value.require) && !value.types) value.types = (value.import ?? value.require)?.replace(/\.js$/, ".d.ts").replace(/\.cjs$/, ".d.cts");
|
|
1273
|
+
return value;
|
|
1274
|
+
}
|
|
1251
1275
|
async function fetchWithRetry(url, init, retries = MAX_FETCH_RETRIES) {
|
|
1252
|
-
|
|
1276
|
+
let urlString;
|
|
1277
|
+
if (typeof url === "string") urlString = url;
|
|
1278
|
+
else if (url instanceof URL) urlString = url.href;
|
|
1279
|
+
else urlString = url.url;
|
|
1253
1280
|
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
1254
1281
|
const controller = new AbortController();
|
|
1255
|
-
const timeout = setTimeout(() =>
|
|
1282
|
+
const timeout = setTimeout(() => {
|
|
1283
|
+
controller.abort();
|
|
1284
|
+
}, FETCH_TIMEOUT_MS);
|
|
1256
1285
|
try {
|
|
1257
1286
|
const response = await fetch(url, {
|
|
1258
1287
|
...init,
|
|
@@ -1260,12 +1289,13 @@ async function fetchWithRetry(url, init, retries = MAX_FETCH_RETRIES) {
|
|
|
1260
1289
|
});
|
|
1261
1290
|
clearTimeout(timeout);
|
|
1262
1291
|
return response;
|
|
1263
|
-
} catch (
|
|
1292
|
+
} catch (err) {
|
|
1264
1293
|
clearTimeout(timeout);
|
|
1265
|
-
const
|
|
1294
|
+
const error$1 = err;
|
|
1295
|
+
const isRetryable = error$1.cause?.code === "ECONNRESET" || error$1.cause?.code === "ETIMEDOUT" || error$1.cause?.code === "UND_ERR_CONNECT_TIMEOUT" || error$1.message.includes("timeout");
|
|
1266
1296
|
if (attempt < retries && isRetryable) {
|
|
1267
1297
|
const delay = attempt * 1e3;
|
|
1268
|
-
warn(`Fetch failed (${error$1
|
|
1298
|
+
warn(`Fetch failed (${error$1.cause?.code ?? error$1.message}) for ${urlString}, retrying in ${delay}ms...`);
|
|
1269
1299
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1270
1300
|
continue;
|
|
1271
1301
|
}
|
|
@@ -1397,11 +1427,12 @@ var FileMetadataCache = class {
|
|
|
1397
1427
|
if (this.pendingPersist) await this.pendingPersist;
|
|
1398
1428
|
}
|
|
1399
1429
|
schedulePersist() {
|
|
1400
|
-
|
|
1401
|
-
if (!
|
|
1430
|
+
const projectDir = this.projectDir;
|
|
1431
|
+
if (!projectDir) return;
|
|
1432
|
+
this.pendingPersist ??= (async () => {
|
|
1402
1433
|
try {
|
|
1403
1434
|
await Promise.resolve();
|
|
1404
|
-
await savePersistedState(
|
|
1435
|
+
await savePersistedState(projectDir, this.persisted);
|
|
1405
1436
|
} finally {
|
|
1406
1437
|
this.pendingPersist = null;
|
|
1407
1438
|
}
|
|
@@ -1420,12 +1451,24 @@ var PluginDisconnectedError = class extends Error {
|
|
|
1420
1451
|
var UserActionCoordinator = class {
|
|
1421
1452
|
pendingActions = /* @__PURE__ */ new Map();
|
|
1422
1453
|
/**
|
|
1454
|
+
* Register a pending action and return a typed promise
|
|
1455
|
+
*/
|
|
1456
|
+
awaitAction(actionId, description) {
|
|
1457
|
+
return new Promise((resolve, reject) => {
|
|
1458
|
+
this.pendingActions.set(actionId, {
|
|
1459
|
+
resolve,
|
|
1460
|
+
reject
|
|
1461
|
+
});
|
|
1462
|
+
debug(`Awaiting ${description}: ${actionId}`);
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1423
1466
|
* Sends the delete request to the plugin and awaits the user's decision
|
|
1424
1467
|
*/
|
|
1425
1468
|
async requestDeleteDecision(socket, { fileName, requireConfirmation }) {
|
|
1426
1469
|
if (!socket) throw new Error("Cannot request delete decision: plugin not connected");
|
|
1427
1470
|
if (requireConfirmation) {
|
|
1428
|
-
const confirmationPromise = this.
|
|
1471
|
+
const confirmationPromise = this.awaitAction(`delete:${fileName}`, "delete confirmation");
|
|
1429
1472
|
await sendMessage(socket, {
|
|
1430
1473
|
type: "file-delete",
|
|
1431
1474
|
fileNames: [fileName],
|
|
@@ -1456,7 +1499,7 @@ var UserActionCoordinator = class {
|
|
|
1456
1499
|
if (conflicts.length === 0) return /* @__PURE__ */ new Map();
|
|
1457
1500
|
const pending = conflicts.map((conflict) => ({
|
|
1458
1501
|
fileName: conflict.fileName,
|
|
1459
|
-
promise: this.
|
|
1502
|
+
promise: this.awaitAction(`conflict:${conflict.fileName}`, "conflict resolution")
|
|
1460
1503
|
}));
|
|
1461
1504
|
await sendMessage(socket, {
|
|
1462
1505
|
type: "conflicts-detected",
|
|
@@ -1474,18 +1517,6 @@ var UserActionCoordinator = class {
|
|
|
1474
1517
|
}
|
|
1475
1518
|
}
|
|
1476
1519
|
/**
|
|
1477
|
-
* Generic confirmation awaiter
|
|
1478
|
-
*/
|
|
1479
|
-
awaitConfirmation(actionId, description) {
|
|
1480
|
-
return new Promise((resolve, reject) => {
|
|
1481
|
-
this.pendingActions.set(actionId, {
|
|
1482
|
-
resolve,
|
|
1483
|
-
reject
|
|
1484
|
-
});
|
|
1485
|
-
debug(`Awaiting ${description}: ${actionId}`);
|
|
1486
|
-
});
|
|
1487
|
-
}
|
|
1488
|
-
/**
|
|
1489
1520
|
* Handle incoming confirmation response
|
|
1490
1521
|
*/
|
|
1491
1522
|
handleConfirmation(actionId, value) {
|
|
@@ -2189,14 +2220,16 @@ async function executeEffect(effect, context) {
|
|
|
2189
2220
|
status("Watching for changes...");
|
|
2190
2221
|
return [];
|
|
2191
2222
|
}
|
|
2192
|
-
case "LOG":
|
|
2193
|
-
|
|
2223
|
+
case "LOG": {
|
|
2224
|
+
const logFn = {
|
|
2194
2225
|
info,
|
|
2195
2226
|
warn,
|
|
2196
2227
|
success,
|
|
2197
2228
|
debug
|
|
2198
|
-
}[effect.level]
|
|
2229
|
+
}[effect.level];
|
|
2230
|
+
logFn(effect.message);
|
|
2199
2231
|
return [];
|
|
2232
|
+
}
|
|
2200
2233
|
}
|
|
2201
2234
|
}
|
|
2202
2235
|
/**
|
|
@@ -2236,7 +2269,7 @@ async function start(config) {
|
|
|
2236
2269
|
}
|
|
2237
2270
|
}
|
|
2238
2271
|
const connection = await initConnection(config.port);
|
|
2239
|
-
connection.on("handshake",
|
|
2272
|
+
connection.on("handshake", (client, message) => {
|
|
2240
2273
|
debug(`Received handshake: ${message.projectName} (${message.projectId})`);
|
|
2241
2274
|
const expectedShort = shortProjectHash(config.projectHash);
|
|
2242
2275
|
const receivedShort = shortProjectHash(message.projectId);
|
|
@@ -2245,24 +2278,26 @@ async function start(config) {
|
|
|
2245
2278
|
client.close();
|
|
2246
2279
|
return;
|
|
2247
2280
|
}
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
if (config.projectDir && !installer) {
|
|
2257
|
-
installer = new Installer({
|
|
2258
|
-
projectDir: config.projectDir,
|
|
2259
|
-
allowUnsupportedNpm: config.allowUnsupportedNpm
|
|
2281
|
+
(async () => {
|
|
2282
|
+
await processEvent({
|
|
2283
|
+
type: "HANDSHAKE",
|
|
2284
|
+
socket: client,
|
|
2285
|
+
projectInfo: {
|
|
2286
|
+
projectId: message.projectId,
|
|
2287
|
+
projectName: message.projectName
|
|
2288
|
+
}
|
|
2260
2289
|
});
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2290
|
+
if (config.projectDir && !installer) {
|
|
2291
|
+
installer = new Installer({
|
|
2292
|
+
projectDir: config.projectDir,
|
|
2293
|
+
allowUnsupportedNpm: config.allowUnsupportedNpm
|
|
2294
|
+
});
|
|
2295
|
+
await installer.initialize();
|
|
2296
|
+
startWatcher();
|
|
2297
|
+
}
|
|
2298
|
+
cancelDisconnectMessage();
|
|
2299
|
+
if (!wasRecentlyDisconnected() && !didShowDisconnect()) success(`Connected to ${message.projectName}`);
|
|
2300
|
+
})();
|
|
2266
2301
|
});
|
|
2267
2302
|
async function handleMessage(message) {
|
|
2268
2303
|
if (!config.projectDir || !installer) {
|
|
@@ -2340,21 +2375,25 @@ async function start(config) {
|
|
|
2340
2375
|
warn(`Unhandled message type: ${message.type}`);
|
|
2341
2376
|
return;
|
|
2342
2377
|
}
|
|
2343
|
-
|
|
2378
|
+
await processEvent(event);
|
|
2344
2379
|
}
|
|
2345
|
-
connection.on("message",
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2380
|
+
connection.on("message", (message) => {
|
|
2381
|
+
(async () => {
|
|
2382
|
+
try {
|
|
2383
|
+
await handleMessage(message);
|
|
2384
|
+
} catch (err) {
|
|
2385
|
+
error("Error handling message:", err);
|
|
2386
|
+
}
|
|
2387
|
+
})();
|
|
2351
2388
|
});
|
|
2352
|
-
connection.on("disconnect",
|
|
2389
|
+
connection.on("disconnect", () => {
|
|
2353
2390
|
scheduleDisconnectMessage(() => {
|
|
2354
2391
|
status("Disconnected, waiting to reconnect...");
|
|
2355
2392
|
});
|
|
2356
|
-
|
|
2357
|
-
|
|
2393
|
+
(async () => {
|
|
2394
|
+
await processEvent({ type: "DISCONNECT" });
|
|
2395
|
+
userActions.cleanup();
|
|
2396
|
+
})();
|
|
2358
2397
|
});
|
|
2359
2398
|
connection.on("error", (err) => {
|
|
2360
2399
|
error("Error on WebSocket connection:", err);
|
|
@@ -2363,19 +2402,21 @@ async function start(config) {
|
|
|
2363
2402
|
const startWatcher = () => {
|
|
2364
2403
|
if (!config.filesDir || watcher) return;
|
|
2365
2404
|
watcher = initWatcher(config.filesDir);
|
|
2366
|
-
watcher.on("change",
|
|
2367
|
-
|
|
2405
|
+
watcher.on("change", (event) => {
|
|
2406
|
+
processEvent({
|
|
2368
2407
|
type: "WATCHER_EVENT",
|
|
2369
2408
|
event
|
|
2370
2409
|
});
|
|
2371
2410
|
});
|
|
2372
2411
|
};
|
|
2373
|
-
process.on("SIGINT",
|
|
2412
|
+
process.on("SIGINT", () => {
|
|
2374
2413
|
console.log();
|
|
2375
2414
|
status("Shutting down...");
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2415
|
+
(async () => {
|
|
2416
|
+
if (watcher) await watcher.close();
|
|
2417
|
+
connection.close();
|
|
2418
|
+
process.exit(0);
|
|
2419
|
+
})();
|
|
2379
2420
|
});
|
|
2380
2421
|
}
|
|
2381
2422
|
|
|
@@ -2392,7 +2433,7 @@ const program = new Command();
|
|
|
2392
2433
|
program.exitOverride((err) => {
|
|
2393
2434
|
if (err.code === "commander.missingArgument") {
|
|
2394
2435
|
console.error("Missing Project ID. Copy command via Code Link Plugin.");
|
|
2395
|
-
process.exit(err.exitCode
|
|
2436
|
+
process.exit(err.exitCode);
|
|
2396
2437
|
}
|
|
2397
2438
|
throw err;
|
|
2398
2439
|
});
|
|
@@ -2406,7 +2447,6 @@ program.name("framer-code-link").description("Sync Framer code components to you
|
|
|
2406
2447
|
process.exit(1);
|
|
2407
2448
|
}
|
|
2408
2449
|
}
|
|
2409
|
-
const isDev = process.env.NODE_ENV === "development";
|
|
2410
2450
|
if (options.logLevel) {
|
|
2411
2451
|
const level = {
|
|
2412
2452
|
debug: LogLevel.DEBUG,
|
|
@@ -2415,7 +2455,7 @@ program.name("framer-code-link").description("Sync Framer code components to you
|
|
|
2415
2455
|
error: LogLevel.ERROR
|
|
2416
2456
|
}[options.logLevel.toLowerCase()];
|
|
2417
2457
|
if (level !== void 0) setLogLevel(level);
|
|
2418
|
-
} else if (options.verbose
|
|
2458
|
+
} else if (options.verbose) setLogLevel(LogLevel.DEBUG);
|
|
2419
2459
|
const port = getPortFromHash(projectHash);
|
|
2420
2460
|
banner(version, port);
|
|
2421
2461
|
const config = {
|