@cryptforge/key-exchange 0.1.0 → 0.2.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.
package/dist/index.mjs CHANGED
@@ -495,11 +495,11 @@ var KeyTransportClient = class {
495
495
  throw error;
496
496
  }
497
497
  };
498
- broadcastClientState = async (id, state) => {
498
+ broadcastClientState = async (id, state, name, isHeartbeat) => {
499
499
  console.log("KeyTransportClient.broadcastClientState");
500
500
  this.peers.set(id, state);
501
501
  try {
502
- await this.sendRequest(MESSAGES.broadcastClientState, { id, state });
502
+ await this.sendRequest(MESSAGES.broadcastClientState, { id, state, name, isHeartbeat });
503
503
  } catch (error) {
504
504
  console.error("Failed to broadcast client state:", error);
505
505
  throw error;
@@ -567,6 +567,98 @@ var KeyTransportClient = class {
567
567
  return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
568
568
  };
569
569
  };
570
+
571
+ // src/devicePairing.ts
572
+ var DevicePairingManager = class {
573
+ storageKey;
574
+ constructor(identityId) {
575
+ this.storageKey = `cryptforge:identity:${identityId}:linked-devices`;
576
+ }
577
+ /**
578
+ * Get all linked devices for this app
579
+ */
580
+ getLinkedDevices = () => {
581
+ try {
582
+ const stored = localStorage.getItem(this.storageKey);
583
+ return stored ? JSON.parse(stored) : [];
584
+ } catch (error) {
585
+ console.error("Failed to load linked devices:", error);
586
+ return [];
587
+ }
588
+ };
589
+ /**
590
+ * Add a device to the linked devices list
591
+ * Called after successful key exchange
592
+ */
593
+ addLinkedDevice = (device) => {
594
+ try {
595
+ const devices = this.getLinkedDevices();
596
+ const existing = devices.find((d) => d.id === device.id);
597
+ if (existing) {
598
+ existing.name = device.name;
599
+ } else {
600
+ devices.push({
601
+ id: device.id,
602
+ name: device.name,
603
+ linkedAt: Date.now()
604
+ });
605
+ }
606
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
607
+ } catch (error) {
608
+ console.error("Failed to add linked device:", error);
609
+ }
610
+ };
611
+ /**
612
+ * Remove a device from the linked devices list
613
+ * For future use when user wants to unlink a device
614
+ */
615
+ removeLinkedDevice = (id) => {
616
+ try {
617
+ const devices = this.getLinkedDevices().filter((d) => d.id !== id);
618
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
619
+ console.log(`Removed linked device: ${id}`);
620
+ } catch (error) {
621
+ console.error("Failed to remove linked device:", error);
622
+ }
623
+ };
624
+ /**
625
+ * Update the hostname of a device (system-level name)
626
+ */
627
+ updateDeviceName = (id, name) => {
628
+ try {
629
+ const devices = this.getLinkedDevices();
630
+ const device = devices.find((d) => d.id === id);
631
+ if (device) {
632
+ device.name = name;
633
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
634
+ }
635
+ } catch (error) {
636
+ console.error("Failed to update device name:", error);
637
+ }
638
+ };
639
+ /**
640
+ * Set a custom user-defined name for a device
641
+ */
642
+ setCustomName = (id, customName) => {
643
+ try {
644
+ const devices = this.getLinkedDevices();
645
+ const device = devices.find((d) => d.id === id);
646
+ if (device) {
647
+ device.customName = customName.trim() || void 0;
648
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
649
+ }
650
+ } catch (error) {
651
+ console.error("Failed to set custom device name:", error);
652
+ }
653
+ };
654
+ /**
655
+ * Check if a device is linked
656
+ */
657
+ isLinked = (id) => {
658
+ return this.getLinkedDevices().some((d) => d.id === id);
659
+ };
660
+ };
570
661
  export {
662
+ DevicePairingManager,
571
663
  KeyTransportClient
572
664
  };
package/dist/server.d.mts CHANGED
@@ -43,4 +43,48 @@ declare class KeyTransportServer {
43
43
  getPort: () => number;
44
44
  }
45
45
 
46
- export { KeyTransportServer, useKeyExchangeServer };
46
+ /**
47
+ * Manages linked devices (devices that have completed key exchange)
48
+ * Stores device info in localStorage scoped per app
49
+ */
50
+ interface LinkedDevice {
51
+ id: string;
52
+ name: string;
53
+ customName?: string;
54
+ linkedAt: number;
55
+ }
56
+ declare class DevicePairingManager {
57
+ private storageKey;
58
+ constructor(identityId: string);
59
+ /**
60
+ * Get all linked devices for this app
61
+ */
62
+ getLinkedDevices: () => LinkedDevice[];
63
+ /**
64
+ * Add a device to the linked devices list
65
+ * Called after successful key exchange
66
+ */
67
+ addLinkedDevice: (device: {
68
+ id: string;
69
+ name: string;
70
+ }) => void;
71
+ /**
72
+ * Remove a device from the linked devices list
73
+ * For future use when user wants to unlink a device
74
+ */
75
+ removeLinkedDevice: (id: string) => void;
76
+ /**
77
+ * Update the hostname of a device (system-level name)
78
+ */
79
+ updateDeviceName: (id: string, name: string) => void;
80
+ /**
81
+ * Set a custom user-defined name for a device
82
+ */
83
+ setCustomName: (id: string, customName: string) => void;
84
+ /**
85
+ * Check if a device is linked
86
+ */
87
+ isLinked: (id: string) => boolean;
88
+ }
89
+
90
+ export { DevicePairingManager, KeyTransportServer, type LinkedDevice, useKeyExchangeServer };
package/dist/server.d.ts CHANGED
@@ -43,4 +43,48 @@ declare class KeyTransportServer {
43
43
  getPort: () => number;
44
44
  }
45
45
 
46
- export { KeyTransportServer, useKeyExchangeServer };
46
+ /**
47
+ * Manages linked devices (devices that have completed key exchange)
48
+ * Stores device info in localStorage scoped per app
49
+ */
50
+ interface LinkedDevice {
51
+ id: string;
52
+ name: string;
53
+ customName?: string;
54
+ linkedAt: number;
55
+ }
56
+ declare class DevicePairingManager {
57
+ private storageKey;
58
+ constructor(identityId: string);
59
+ /**
60
+ * Get all linked devices for this app
61
+ */
62
+ getLinkedDevices: () => LinkedDevice[];
63
+ /**
64
+ * Add a device to the linked devices list
65
+ * Called after successful key exchange
66
+ */
67
+ addLinkedDevice: (device: {
68
+ id: string;
69
+ name: string;
70
+ }) => void;
71
+ /**
72
+ * Remove a device from the linked devices list
73
+ * For future use when user wants to unlink a device
74
+ */
75
+ removeLinkedDevice: (id: string) => void;
76
+ /**
77
+ * Update the hostname of a device (system-level name)
78
+ */
79
+ updateDeviceName: (id: string, name: string) => void;
80
+ /**
81
+ * Set a custom user-defined name for a device
82
+ */
83
+ setCustomName: (id: string, customName: string) => void;
84
+ /**
85
+ * Check if a device is linked
86
+ */
87
+ isLinked: (id: string) => boolean;
88
+ }
89
+
90
+ export { DevicePairingManager, KeyTransportServer, type LinkedDevice, useKeyExchangeServer };
package/dist/server.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/server.ts
31
31
  var server_exports = {};
32
32
  __export(server_exports, {
33
+ DevicePairingManager: () => DevicePairingManager,
33
34
  KeyTransportServer: () => KeyTransportServer,
34
35
  useKeyExchangeServer: () => useKeyExchangeServer
35
36
  });
@@ -275,7 +276,7 @@ function useKeyExchangeServer(onEvent) {
275
276
  });
276
277
  };
277
278
  const completeSetupSuccess = async () => {
278
- console.log("sending compltion message to client");
279
+ console.log("sending completion message to client");
279
280
  sendResponse({
280
281
  to: [client],
281
282
  header: "Setup Succeeded",
@@ -329,16 +330,9 @@ function useNetworkPresence(onUpdate, onRequest) {
329
330
  const swarm = new import_hyperswarm.default();
330
331
  swarm.on("connection", (connection) => {
331
332
  const name = import_b4a3.default.toString(connection.remotePublicKey, "hex");
332
- console.log("Presence: * got a connection from:", name, "*");
333
333
  connections.push(connection);
334
334
  sendStateRequestMessage(connection);
335
335
  connection.once("close", () => {
336
- console.log(
337
- `Presence: Connection closed. Removing connection ${import_b4a3.default.toString(
338
- connection.remotePublicKey,
339
- "hex"
340
- )}`
341
- );
342
336
  connections.splice(connections.indexOf(connection), 1);
343
337
  const id = deviceIDs.get(import_b4a3.default.toString(connection.remotePublicKey, "hex"));
344
338
  if (id) {
@@ -351,17 +345,18 @@ function useNetworkPresence(onUpdate, onRequest) {
351
345
  try {
352
346
  parsedData = JSON.parse(data);
353
347
  } catch (error) {
354
- console.error("Error parsing data:", error);
348
+ console.error("Error parsing presence data:", error);
355
349
  return;
356
350
  }
357
351
  const header = parsedData;
358
- console.log(
359
- "Presence: got data for ",
360
- connection.publicKey.toString("hex")
361
- );
362
352
  if (header.type === "update") {
363
353
  const payload = parsedData;
364
- onUpdate({ id: payload.id, state: payload.state });
354
+ onUpdate({
355
+ id: payload.id,
356
+ state: payload.state,
357
+ name: payload.name,
358
+ isHeartbeat: payload.isHeartbeat
359
+ });
365
360
  deviceIDs.set(
366
361
  import_b4a3.default.toString(connection.remotePublicKey, "hex"),
367
362
  payload.id
@@ -381,46 +376,35 @@ function useNetworkPresence(onUpdate, onRequest) {
381
376
  });
382
377
  const connections = [];
383
378
  const connect = async (topic, id) => {
384
- console.log("Presence: connecting to topic: ", topic);
385
379
  const key = import_b4a3.default.from(topic, "hex");
386
- console.log("key: ", key);
387
380
  const discovery = swarm.join(key, { client: true, server: true });
388
- console.log("got discovery: ");
389
381
  const publicKey = import_b4a3.default.toString(
390
382
  discovery.swarm.keyPair?.publicKey || discovery.swarm.publicKey || Buffer.alloc(32),
391
383
  "hex"
392
384
  );
393
- console.log("Presence: public key is ", publicKey);
394
385
  deviceIDs.set(publicKey, id);
395
- discovery.flushed().then(() => {
396
- console.log("Presence: joined topic:", import_b4a3.default.toString(key, "hex"));
397
- });
386
+ await discovery.flushed();
398
387
  };
399
388
  const sendStateRequestMessage = async (connection) => {
400
389
  const message = {
401
390
  type: "request"
402
391
  };
403
392
  const payload = JSON.stringify(message);
404
- console.log(
405
- "sending state request message to: ",
406
- connection.publicKey.toString("hex")
407
- );
408
393
  connection.write(payload);
409
394
  };
410
- const receiveStatusMessage = async (id, state) => {
411
- return broadcastStatusMessage(id, state);
395
+ const receiveStatusMessage = async (id, state, name, isHeartbeat) => {
396
+ return broadcastStatusMessage(id, state, name, isHeartbeat);
412
397
  };
413
- const broadcastStatusMessage = (id, state) => {
414
- console.log(`server got connection state message for ${id}: `, state);
398
+ const broadcastStatusMessage = (id, state, name, isHeartbeat) => {
415
399
  const message = {
416
400
  type: "update",
417
401
  id,
418
- state
402
+ state,
403
+ name,
404
+ isHeartbeat
419
405
  };
420
- console.log("active connections: ", connections.length);
421
406
  const payload = JSON.stringify(message);
422
407
  for (const connection of connections) {
423
- console.log("sending message to: ", connection.publicKey.toString("hex"));
424
408
  connection.write(payload);
425
409
  }
426
410
  onUpdate(message);
@@ -688,8 +672,8 @@ var CoreTransportLogic = class {
688
672
  await this.presence.connect(topicHash, deviceInfo.id);
689
673
  this.presenceConnected = true;
690
674
  }
691
- broadcastClientState(id, state) {
692
- this.presence.receiveStatusMessage(id, state);
675
+ broadcastClientState(id, state, name, isHeartbeat) {
676
+ this.presence.receiveStatusMessage(id, state, name, isHeartbeat);
693
677
  }
694
678
  };
695
679
 
@@ -892,7 +876,7 @@ var KeyTransportServer = class {
892
876
  case MESSAGES.broadcastClientState:
893
877
  this.logger?.log("\u{1F4E1} Broadcasting client state...");
894
878
  try {
895
- this.core.broadcastClientState(requestData.id, requestData.state);
879
+ this.core.broadcastClientState(requestData.id, requestData.state, requestData.isHeartbeat);
896
880
  this.sendResponse(ws, type, requestId, { success: true });
897
881
  } catch (error) {
898
882
  this.sendResponse(ws, type, requestId, null, {
@@ -933,8 +917,100 @@ var KeyTransportServer = class {
933
917
  return this.port;
934
918
  };
935
919
  };
920
+
921
+ // src/devicePairing.ts
922
+ var DevicePairingManager = class {
923
+ storageKey;
924
+ constructor(identityId) {
925
+ this.storageKey = `cryptforge:identity:${identityId}:linked-devices`;
926
+ }
927
+ /**
928
+ * Get all linked devices for this app
929
+ */
930
+ getLinkedDevices = () => {
931
+ try {
932
+ const stored = localStorage.getItem(this.storageKey);
933
+ return stored ? JSON.parse(stored) : [];
934
+ } catch (error) {
935
+ console.error("Failed to load linked devices:", error);
936
+ return [];
937
+ }
938
+ };
939
+ /**
940
+ * Add a device to the linked devices list
941
+ * Called after successful key exchange
942
+ */
943
+ addLinkedDevice = (device) => {
944
+ try {
945
+ const devices = this.getLinkedDevices();
946
+ const existing = devices.find((d) => d.id === device.id);
947
+ if (existing) {
948
+ existing.name = device.name;
949
+ } else {
950
+ devices.push({
951
+ id: device.id,
952
+ name: device.name,
953
+ linkedAt: Date.now()
954
+ });
955
+ }
956
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
957
+ } catch (error) {
958
+ console.error("Failed to add linked device:", error);
959
+ }
960
+ };
961
+ /**
962
+ * Remove a device from the linked devices list
963
+ * For future use when user wants to unlink a device
964
+ */
965
+ removeLinkedDevice = (id) => {
966
+ try {
967
+ const devices = this.getLinkedDevices().filter((d) => d.id !== id);
968
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
969
+ console.log(`Removed linked device: ${id}`);
970
+ } catch (error) {
971
+ console.error("Failed to remove linked device:", error);
972
+ }
973
+ };
974
+ /**
975
+ * Update the hostname of a device (system-level name)
976
+ */
977
+ updateDeviceName = (id, name) => {
978
+ try {
979
+ const devices = this.getLinkedDevices();
980
+ const device = devices.find((d) => d.id === id);
981
+ if (device) {
982
+ device.name = name;
983
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
984
+ }
985
+ } catch (error) {
986
+ console.error("Failed to update device name:", error);
987
+ }
988
+ };
989
+ /**
990
+ * Set a custom user-defined name for a device
991
+ */
992
+ setCustomName = (id, customName) => {
993
+ try {
994
+ const devices = this.getLinkedDevices();
995
+ const device = devices.find((d) => d.id === id);
996
+ if (device) {
997
+ device.customName = customName.trim() || void 0;
998
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
999
+ }
1000
+ } catch (error) {
1001
+ console.error("Failed to set custom device name:", error);
1002
+ }
1003
+ };
1004
+ /**
1005
+ * Check if a device is linked
1006
+ */
1007
+ isLinked = (id) => {
1008
+ return this.getLinkedDevices().some((d) => d.id === id);
1009
+ };
1010
+ };
936
1011
  // Annotate the CommonJS export names for ESM import in node:
937
1012
  0 && (module.exports = {
1013
+ DevicePairingManager,
938
1014
  KeyTransportServer,
939
1015
  useKeyExchangeServer
940
1016
  });
package/dist/server.mjs CHANGED
@@ -238,7 +238,7 @@ function useKeyExchangeServer(onEvent) {
238
238
  });
239
239
  };
240
240
  const completeSetupSuccess = async () => {
241
- console.log("sending compltion message to client");
241
+ console.log("sending completion message to client");
242
242
  sendResponse({
243
243
  to: [client],
244
244
  header: "Setup Succeeded",
@@ -292,16 +292,9 @@ function useNetworkPresence(onUpdate, onRequest) {
292
292
  const swarm = new Hyperswarm();
293
293
  swarm.on("connection", (connection) => {
294
294
  const name = b4a3.toString(connection.remotePublicKey, "hex");
295
- console.log("Presence: * got a connection from:", name, "*");
296
295
  connections.push(connection);
297
296
  sendStateRequestMessage(connection);
298
297
  connection.once("close", () => {
299
- console.log(
300
- `Presence: Connection closed. Removing connection ${b4a3.toString(
301
- connection.remotePublicKey,
302
- "hex"
303
- )}`
304
- );
305
298
  connections.splice(connections.indexOf(connection), 1);
306
299
  const id = deviceIDs.get(b4a3.toString(connection.remotePublicKey, "hex"));
307
300
  if (id) {
@@ -314,17 +307,18 @@ function useNetworkPresence(onUpdate, onRequest) {
314
307
  try {
315
308
  parsedData = JSON.parse(data);
316
309
  } catch (error) {
317
- console.error("Error parsing data:", error);
310
+ console.error("Error parsing presence data:", error);
318
311
  return;
319
312
  }
320
313
  const header = parsedData;
321
- console.log(
322
- "Presence: got data for ",
323
- connection.publicKey.toString("hex")
324
- );
325
314
  if (header.type === "update") {
326
315
  const payload = parsedData;
327
- onUpdate({ id: payload.id, state: payload.state });
316
+ onUpdate({
317
+ id: payload.id,
318
+ state: payload.state,
319
+ name: payload.name,
320
+ isHeartbeat: payload.isHeartbeat
321
+ });
328
322
  deviceIDs.set(
329
323
  b4a3.toString(connection.remotePublicKey, "hex"),
330
324
  payload.id
@@ -344,46 +338,35 @@ function useNetworkPresence(onUpdate, onRequest) {
344
338
  });
345
339
  const connections = [];
346
340
  const connect = async (topic, id) => {
347
- console.log("Presence: connecting to topic: ", topic);
348
341
  const key = b4a3.from(topic, "hex");
349
- console.log("key: ", key);
350
342
  const discovery = swarm.join(key, { client: true, server: true });
351
- console.log("got discovery: ");
352
343
  const publicKey = b4a3.toString(
353
344
  discovery.swarm.keyPair?.publicKey || discovery.swarm.publicKey || Buffer.alloc(32),
354
345
  "hex"
355
346
  );
356
- console.log("Presence: public key is ", publicKey);
357
347
  deviceIDs.set(publicKey, id);
358
- discovery.flushed().then(() => {
359
- console.log("Presence: joined topic:", b4a3.toString(key, "hex"));
360
- });
348
+ await discovery.flushed();
361
349
  };
362
350
  const sendStateRequestMessage = async (connection) => {
363
351
  const message = {
364
352
  type: "request"
365
353
  };
366
354
  const payload = JSON.stringify(message);
367
- console.log(
368
- "sending state request message to: ",
369
- connection.publicKey.toString("hex")
370
- );
371
355
  connection.write(payload);
372
356
  };
373
- const receiveStatusMessage = async (id, state) => {
374
- return broadcastStatusMessage(id, state);
357
+ const receiveStatusMessage = async (id, state, name, isHeartbeat) => {
358
+ return broadcastStatusMessage(id, state, name, isHeartbeat);
375
359
  };
376
- const broadcastStatusMessage = (id, state) => {
377
- console.log(`server got connection state message for ${id}: `, state);
360
+ const broadcastStatusMessage = (id, state, name, isHeartbeat) => {
378
361
  const message = {
379
362
  type: "update",
380
363
  id,
381
- state
364
+ state,
365
+ name,
366
+ isHeartbeat
382
367
  };
383
- console.log("active connections: ", connections.length);
384
368
  const payload = JSON.stringify(message);
385
369
  for (const connection of connections) {
386
- console.log("sending message to: ", connection.publicKey.toString("hex"));
387
370
  connection.write(payload);
388
371
  }
389
372
  onUpdate(message);
@@ -651,8 +634,8 @@ var CoreTransportLogic = class {
651
634
  await this.presence.connect(topicHash, deviceInfo.id);
652
635
  this.presenceConnected = true;
653
636
  }
654
- broadcastClientState(id, state) {
655
- this.presence.receiveStatusMessage(id, state);
637
+ broadcastClientState(id, state, name, isHeartbeat) {
638
+ this.presence.receiveStatusMessage(id, state, name, isHeartbeat);
656
639
  }
657
640
  };
658
641
 
@@ -855,7 +838,7 @@ var KeyTransportServer = class {
855
838
  case MESSAGES.broadcastClientState:
856
839
  this.logger?.log("\u{1F4E1} Broadcasting client state...");
857
840
  try {
858
- this.core.broadcastClientState(requestData.id, requestData.state);
841
+ this.core.broadcastClientState(requestData.id, requestData.state, requestData.isHeartbeat);
859
842
  this.sendResponse(ws, type, requestId, { success: true });
860
843
  } catch (error) {
861
844
  this.sendResponse(ws, type, requestId, null, {
@@ -896,7 +879,99 @@ var KeyTransportServer = class {
896
879
  return this.port;
897
880
  };
898
881
  };
882
+
883
+ // src/devicePairing.ts
884
+ var DevicePairingManager = class {
885
+ storageKey;
886
+ constructor(identityId) {
887
+ this.storageKey = `cryptforge:identity:${identityId}:linked-devices`;
888
+ }
889
+ /**
890
+ * Get all linked devices for this app
891
+ */
892
+ getLinkedDevices = () => {
893
+ try {
894
+ const stored = localStorage.getItem(this.storageKey);
895
+ return stored ? JSON.parse(stored) : [];
896
+ } catch (error) {
897
+ console.error("Failed to load linked devices:", error);
898
+ return [];
899
+ }
900
+ };
901
+ /**
902
+ * Add a device to the linked devices list
903
+ * Called after successful key exchange
904
+ */
905
+ addLinkedDevice = (device) => {
906
+ try {
907
+ const devices = this.getLinkedDevices();
908
+ const existing = devices.find((d) => d.id === device.id);
909
+ if (existing) {
910
+ existing.name = device.name;
911
+ } else {
912
+ devices.push({
913
+ id: device.id,
914
+ name: device.name,
915
+ linkedAt: Date.now()
916
+ });
917
+ }
918
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
919
+ } catch (error) {
920
+ console.error("Failed to add linked device:", error);
921
+ }
922
+ };
923
+ /**
924
+ * Remove a device from the linked devices list
925
+ * For future use when user wants to unlink a device
926
+ */
927
+ removeLinkedDevice = (id) => {
928
+ try {
929
+ const devices = this.getLinkedDevices().filter((d) => d.id !== id);
930
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
931
+ console.log(`Removed linked device: ${id}`);
932
+ } catch (error) {
933
+ console.error("Failed to remove linked device:", error);
934
+ }
935
+ };
936
+ /**
937
+ * Update the hostname of a device (system-level name)
938
+ */
939
+ updateDeviceName = (id, name) => {
940
+ try {
941
+ const devices = this.getLinkedDevices();
942
+ const device = devices.find((d) => d.id === id);
943
+ if (device) {
944
+ device.name = name;
945
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
946
+ }
947
+ } catch (error) {
948
+ console.error("Failed to update device name:", error);
949
+ }
950
+ };
951
+ /**
952
+ * Set a custom user-defined name for a device
953
+ */
954
+ setCustomName = (id, customName) => {
955
+ try {
956
+ const devices = this.getLinkedDevices();
957
+ const device = devices.find((d) => d.id === id);
958
+ if (device) {
959
+ device.customName = customName.trim() || void 0;
960
+ localStorage.setItem(this.storageKey, JSON.stringify(devices));
961
+ }
962
+ } catch (error) {
963
+ console.error("Failed to set custom device name:", error);
964
+ }
965
+ };
966
+ /**
967
+ * Check if a device is linked
968
+ */
969
+ isLinked = (id) => {
970
+ return this.getLinkedDevices().some((d) => d.id === id);
971
+ };
972
+ };
899
973
  export {
974
+ DevicePairingManager,
900
975
  KeyTransportServer,
901
976
  useKeyExchangeServer
902
977
  };
@@ -0,0 +1,23 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ /**
4
+ * Vite plugin that automatically externalizes native Node.js modules
5
+ * required by @cryptforge/key-exchange for Electron main process builds.
6
+ *
7
+ * This prevents Vite from trying to bundle native modules, which would fail.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // vite.main.config.ts
12
+ * import { defineConfig } from "vite";
13
+ * import { cryptforgeMainPlugin } from "@cryptforge/key-exchange/vite";
14
+ *
15
+ * export default defineConfig({
16
+ * plugins: [cryptforgeMainPlugin()],
17
+ * // ... rest of config
18
+ * });
19
+ * ```
20
+ */
21
+ declare const cryptforgeMainPlugin: () => Plugin;
22
+
23
+ export { cryptforgeMainPlugin };