@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/README.md +55 -0
- package/dist/electron-main.d.mts +1 -1
- package/dist/electron-main.d.ts +1 -1
- package/dist/electron-main.js +21 -38
- package/dist/electron-main.mjs +21 -38
- package/dist/electron-preload.js +1 -1
- package/dist/electron-preload.mjs +1 -1
- package/dist/electron-renderer.d.mts +2 -2
- package/dist/electron-renderer.d.ts +2 -2
- package/dist/electron-renderer.js +2 -2
- package/dist/electron-renderer.mjs +2 -2
- package/dist/index.d.mts +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +95 -2
- package/dist/index.mjs +94 -2
- package/dist/server.d.mts +45 -1
- package/dist/server.d.ts +45 -1
- package/dist/server.js +111 -35
- package/dist/server.mjs +110 -35
- package/dist/vite.d.mts +23 -0
- package/dist/vite.d.ts +23 -0
- package/dist/vite.js +76 -0
- package/dist/vite.mjs +51 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -103,6 +103,61 @@ src/
|
|
|
103
103
|
- WebSocket-based communication for web/browser
|
|
104
104
|
- Hyperswarm support for server-to-server
|
|
105
105
|
|
|
106
|
+
## Vite Plugin (Electron Main Process)
|
|
107
|
+
|
|
108
|
+
When building Electron apps with Vite, native Node.js modules need to be externalized to prevent bundling errors. The package includes a Vite plugin that automatically handles this for you.
|
|
109
|
+
|
|
110
|
+
### Usage
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// vite.main.config.ts (for Electron main process)
|
|
114
|
+
import { defineConfig } from "vite";
|
|
115
|
+
import { cryptforgeMainPlugin } from "@cryptforge/key-exchange/vite";
|
|
116
|
+
|
|
117
|
+
export default defineConfig({
|
|
118
|
+
plugins: [cryptforgeMainPlugin()],
|
|
119
|
+
// ... rest of your config
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### What it does
|
|
124
|
+
|
|
125
|
+
The plugin automatically externalizes these native modules:
|
|
126
|
+
- `hyperswarm`, `hyperdht`, `udx-native`, `utp-native`
|
|
127
|
+
- `sodium-native`, `hypercore`, `hypercore-crypto`
|
|
128
|
+
- `random-access-file`, `compact-encoding`, `b4a`
|
|
129
|
+
- `@cryptforge/key-exchange`
|
|
130
|
+
|
|
131
|
+
### Without the plugin
|
|
132
|
+
|
|
133
|
+
If you prefer manual configuration or need to customize, you can add externals manually:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
export default defineConfig({
|
|
137
|
+
build: {
|
|
138
|
+
rollupOptions: {
|
|
139
|
+
external: [
|
|
140
|
+
"hyperswarm",
|
|
141
|
+
"hyperdht",
|
|
142
|
+
"udx-native",
|
|
143
|
+
// ... other native modules
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Important Notes
|
|
151
|
+
|
|
152
|
+
- ⚠️ **Only use this plugin for Electron main process builds**
|
|
153
|
+
- ✅ The plugin merges with your existing `external` configuration
|
|
154
|
+
- ✅ Works with both array and function forms of `external`
|
|
155
|
+
- ✅ Supports custom build tools that use Rollup
|
|
156
|
+
|
|
157
|
+
## Additional Documentation
|
|
158
|
+
|
|
159
|
+
- **[USAGE_EXAMPLES.md](./USAGE_EXAMPLES.md)** - Additional usage examples for different environments
|
|
160
|
+
|
|
106
161
|
## License
|
|
107
162
|
|
|
108
163
|
ISC
|
package/dist/electron-main.d.mts
CHANGED
|
@@ -35,7 +35,7 @@ declare class CoreTransportLogic {
|
|
|
35
35
|
getDeviceInfo(): Promise<DeviceInfo>;
|
|
36
36
|
getHostname(): Promise<string>;
|
|
37
37
|
connectPresence(topic: string): Promise<void>;
|
|
38
|
-
broadcastClientState(id: string, state: ClientConnectionState): void;
|
|
38
|
+
broadcastClientState(id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean): void;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export { CoreTransportLogic, setupKeyExchangeHandlers };
|
package/dist/electron-main.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ declare class CoreTransportLogic {
|
|
|
35
35
|
getDeviceInfo(): Promise<DeviceInfo>;
|
|
36
36
|
getHostname(): Promise<string>;
|
|
37
37
|
connectPresence(topic: string): Promise<void>;
|
|
38
|
-
broadcastClientState(id: string, state: ClientConnectionState): void;
|
|
38
|
+
broadcastClientState(id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean): void;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export { CoreTransportLogic, setupKeyExchangeHandlers };
|
package/dist/electron-main.js
CHANGED
|
@@ -71,16 +71,9 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
71
71
|
const swarm = new import_hyperswarm.default();
|
|
72
72
|
swarm.on("connection", (connection) => {
|
|
73
73
|
const name = import_b4a.default.toString(connection.remotePublicKey, "hex");
|
|
74
|
-
console.log("Presence: * got a connection from:", name, "*");
|
|
75
74
|
connections.push(connection);
|
|
76
75
|
sendStateRequestMessage(connection);
|
|
77
76
|
connection.once("close", () => {
|
|
78
|
-
console.log(
|
|
79
|
-
`Presence: Connection closed. Removing connection ${import_b4a.default.toString(
|
|
80
|
-
connection.remotePublicKey,
|
|
81
|
-
"hex"
|
|
82
|
-
)}`
|
|
83
|
-
);
|
|
84
77
|
connections.splice(connections.indexOf(connection), 1);
|
|
85
78
|
const id = deviceIDs.get(import_b4a.default.toString(connection.remotePublicKey, "hex"));
|
|
86
79
|
if (id) {
|
|
@@ -93,17 +86,18 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
93
86
|
try {
|
|
94
87
|
parsedData = JSON.parse(data);
|
|
95
88
|
} catch (error) {
|
|
96
|
-
console.error("Error parsing data:", error);
|
|
89
|
+
console.error("Error parsing presence data:", error);
|
|
97
90
|
return;
|
|
98
91
|
}
|
|
99
92
|
const header = parsedData;
|
|
100
|
-
console.log(
|
|
101
|
-
"Presence: got data for ",
|
|
102
|
-
connection.publicKey.toString("hex")
|
|
103
|
-
);
|
|
104
93
|
if (header.type === "update") {
|
|
105
94
|
const payload = parsedData;
|
|
106
|
-
onUpdate({
|
|
95
|
+
onUpdate({
|
|
96
|
+
id: payload.id,
|
|
97
|
+
state: payload.state,
|
|
98
|
+
name: payload.name,
|
|
99
|
+
isHeartbeat: payload.isHeartbeat
|
|
100
|
+
});
|
|
107
101
|
deviceIDs.set(
|
|
108
102
|
import_b4a.default.toString(connection.remotePublicKey, "hex"),
|
|
109
103
|
payload.id
|
|
@@ -123,46 +117,35 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
123
117
|
});
|
|
124
118
|
const connections = [];
|
|
125
119
|
const connect = async (topic, id) => {
|
|
126
|
-
console.log("Presence: connecting to topic: ", topic);
|
|
127
120
|
const key = import_b4a.default.from(topic, "hex");
|
|
128
|
-
console.log("key: ", key);
|
|
129
121
|
const discovery = swarm.join(key, { client: true, server: true });
|
|
130
|
-
console.log("got discovery: ");
|
|
131
122
|
const publicKey = import_b4a.default.toString(
|
|
132
123
|
discovery.swarm.keyPair?.publicKey || discovery.swarm.publicKey || Buffer.alloc(32),
|
|
133
124
|
"hex"
|
|
134
125
|
);
|
|
135
|
-
console.log("Presence: public key is ", publicKey);
|
|
136
126
|
deviceIDs.set(publicKey, id);
|
|
137
|
-
discovery.flushed()
|
|
138
|
-
console.log("Presence: joined topic:", import_b4a.default.toString(key, "hex"));
|
|
139
|
-
});
|
|
127
|
+
await discovery.flushed();
|
|
140
128
|
};
|
|
141
129
|
const sendStateRequestMessage = async (connection) => {
|
|
142
130
|
const message = {
|
|
143
131
|
type: "request"
|
|
144
132
|
};
|
|
145
133
|
const payload = JSON.stringify(message);
|
|
146
|
-
console.log(
|
|
147
|
-
"sending state request message to: ",
|
|
148
|
-
connection.publicKey.toString("hex")
|
|
149
|
-
);
|
|
150
134
|
connection.write(payload);
|
|
151
135
|
};
|
|
152
|
-
const receiveStatusMessage = async (id, state) => {
|
|
153
|
-
return broadcastStatusMessage(id, state);
|
|
136
|
+
const receiveStatusMessage = async (id, state, name, isHeartbeat) => {
|
|
137
|
+
return broadcastStatusMessage(id, state, name, isHeartbeat);
|
|
154
138
|
};
|
|
155
|
-
const broadcastStatusMessage = (id, state) => {
|
|
156
|
-
console.log(`server got connection state message for ${id}: `, state);
|
|
139
|
+
const broadcastStatusMessage = (id, state, name, isHeartbeat) => {
|
|
157
140
|
const message = {
|
|
158
141
|
type: "update",
|
|
159
142
|
id,
|
|
160
|
-
state
|
|
143
|
+
state,
|
|
144
|
+
name,
|
|
145
|
+
isHeartbeat
|
|
161
146
|
};
|
|
162
|
-
console.log("active connections: ", connections.length);
|
|
163
147
|
const payload = JSON.stringify(message);
|
|
164
148
|
for (const connection of connections) {
|
|
165
|
-
console.log("sending message to: ", connection.publicKey.toString("hex"));
|
|
166
149
|
connection.write(payload);
|
|
167
150
|
}
|
|
168
151
|
onUpdate(message);
|
|
@@ -513,7 +496,7 @@ function useKeyExchangeServer(onEvent) {
|
|
|
513
496
|
});
|
|
514
497
|
};
|
|
515
498
|
const completeSetupSuccess = async () => {
|
|
516
|
-
console.log("sending
|
|
499
|
+
console.log("sending completion message to client");
|
|
517
500
|
sendResponse({
|
|
518
501
|
to: [client],
|
|
519
502
|
header: "Setup Succeeded",
|
|
@@ -686,8 +669,8 @@ var CoreTransportLogic = class {
|
|
|
686
669
|
await this.presence.connect(topicHash, deviceInfo.id);
|
|
687
670
|
this.presenceConnected = true;
|
|
688
671
|
}
|
|
689
|
-
broadcastClientState(id, state) {
|
|
690
|
-
this.presence.receiveStatusMessage(id, state);
|
|
672
|
+
broadcastClientState(id, state, name, isHeartbeat) {
|
|
673
|
+
this.presence.receiveStatusMessage(id, state, name, isHeartbeat);
|
|
691
674
|
}
|
|
692
675
|
};
|
|
693
676
|
|
|
@@ -740,9 +723,9 @@ var KeyTransportMain = class {
|
|
|
740
723
|
connectPresence = async (topic) => {
|
|
741
724
|
return this.core.connectPresence(topic);
|
|
742
725
|
};
|
|
743
|
-
broadcastClientState = async (id, state) => {
|
|
726
|
+
broadcastClientState = async (id, state, name, isHeartbeat) => {
|
|
744
727
|
this.peers.set(id, state);
|
|
745
|
-
this.core.broadcastClientState(id, state);
|
|
728
|
+
this.core.broadcastClientState(id, state, name, isHeartbeat);
|
|
746
729
|
};
|
|
747
730
|
onClientStateRequest = async (_callback) => {
|
|
748
731
|
};
|
|
@@ -794,8 +777,8 @@ var setupKeyExchangeHandlers = () => {
|
|
|
794
777
|
});
|
|
795
778
|
import_electron2.ipcMain.handle(
|
|
796
779
|
MESSAGES.broadcastClientState,
|
|
797
|
-
async (_event, id, state) => {
|
|
798
|
-
return transport.broadcastClientState(id, state);
|
|
780
|
+
async (_event, id, state, name, isHeartbeat) => {
|
|
781
|
+
return transport.broadcastClientState(id, state, name, isHeartbeat);
|
|
799
782
|
}
|
|
800
783
|
);
|
|
801
784
|
};
|
package/dist/electron-main.mjs
CHANGED
|
@@ -34,16 +34,9 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
34
34
|
const swarm = new Hyperswarm();
|
|
35
35
|
swarm.on("connection", (connection) => {
|
|
36
36
|
const name = b4a.toString(connection.remotePublicKey, "hex");
|
|
37
|
-
console.log("Presence: * got a connection from:", name, "*");
|
|
38
37
|
connections.push(connection);
|
|
39
38
|
sendStateRequestMessage(connection);
|
|
40
39
|
connection.once("close", () => {
|
|
41
|
-
console.log(
|
|
42
|
-
`Presence: Connection closed. Removing connection ${b4a.toString(
|
|
43
|
-
connection.remotePublicKey,
|
|
44
|
-
"hex"
|
|
45
|
-
)}`
|
|
46
|
-
);
|
|
47
40
|
connections.splice(connections.indexOf(connection), 1);
|
|
48
41
|
const id = deviceIDs.get(b4a.toString(connection.remotePublicKey, "hex"));
|
|
49
42
|
if (id) {
|
|
@@ -56,17 +49,18 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
56
49
|
try {
|
|
57
50
|
parsedData = JSON.parse(data);
|
|
58
51
|
} catch (error) {
|
|
59
|
-
console.error("Error parsing data:", error);
|
|
52
|
+
console.error("Error parsing presence data:", error);
|
|
60
53
|
return;
|
|
61
54
|
}
|
|
62
55
|
const header = parsedData;
|
|
63
|
-
console.log(
|
|
64
|
-
"Presence: got data for ",
|
|
65
|
-
connection.publicKey.toString("hex")
|
|
66
|
-
);
|
|
67
56
|
if (header.type === "update") {
|
|
68
57
|
const payload = parsedData;
|
|
69
|
-
onUpdate({
|
|
58
|
+
onUpdate({
|
|
59
|
+
id: payload.id,
|
|
60
|
+
state: payload.state,
|
|
61
|
+
name: payload.name,
|
|
62
|
+
isHeartbeat: payload.isHeartbeat
|
|
63
|
+
});
|
|
70
64
|
deviceIDs.set(
|
|
71
65
|
b4a.toString(connection.remotePublicKey, "hex"),
|
|
72
66
|
payload.id
|
|
@@ -86,46 +80,35 @@ function useNetworkPresence(onUpdate, onRequest) {
|
|
|
86
80
|
});
|
|
87
81
|
const connections = [];
|
|
88
82
|
const connect = async (topic, id) => {
|
|
89
|
-
console.log("Presence: connecting to topic: ", topic);
|
|
90
83
|
const key = b4a.from(topic, "hex");
|
|
91
|
-
console.log("key: ", key);
|
|
92
84
|
const discovery = swarm.join(key, { client: true, server: true });
|
|
93
|
-
console.log("got discovery: ");
|
|
94
85
|
const publicKey = b4a.toString(
|
|
95
86
|
discovery.swarm.keyPair?.publicKey || discovery.swarm.publicKey || Buffer.alloc(32),
|
|
96
87
|
"hex"
|
|
97
88
|
);
|
|
98
|
-
console.log("Presence: public key is ", publicKey);
|
|
99
89
|
deviceIDs.set(publicKey, id);
|
|
100
|
-
discovery.flushed()
|
|
101
|
-
console.log("Presence: joined topic:", b4a.toString(key, "hex"));
|
|
102
|
-
});
|
|
90
|
+
await discovery.flushed();
|
|
103
91
|
};
|
|
104
92
|
const sendStateRequestMessage = async (connection) => {
|
|
105
93
|
const message = {
|
|
106
94
|
type: "request"
|
|
107
95
|
};
|
|
108
96
|
const payload = JSON.stringify(message);
|
|
109
|
-
console.log(
|
|
110
|
-
"sending state request message to: ",
|
|
111
|
-
connection.publicKey.toString("hex")
|
|
112
|
-
);
|
|
113
97
|
connection.write(payload);
|
|
114
98
|
};
|
|
115
|
-
const receiveStatusMessage = async (id, state) => {
|
|
116
|
-
return broadcastStatusMessage(id, state);
|
|
99
|
+
const receiveStatusMessage = async (id, state, name, isHeartbeat) => {
|
|
100
|
+
return broadcastStatusMessage(id, state, name, isHeartbeat);
|
|
117
101
|
};
|
|
118
|
-
const broadcastStatusMessage = (id, state) => {
|
|
119
|
-
console.log(`server got connection state message for ${id}: `, state);
|
|
102
|
+
const broadcastStatusMessage = (id, state, name, isHeartbeat) => {
|
|
120
103
|
const message = {
|
|
121
104
|
type: "update",
|
|
122
105
|
id,
|
|
123
|
-
state
|
|
106
|
+
state,
|
|
107
|
+
name,
|
|
108
|
+
isHeartbeat
|
|
124
109
|
};
|
|
125
|
-
console.log("active connections: ", connections.length);
|
|
126
110
|
const payload = JSON.stringify(message);
|
|
127
111
|
for (const connection of connections) {
|
|
128
|
-
console.log("sending message to: ", connection.publicKey.toString("hex"));
|
|
129
112
|
connection.write(payload);
|
|
130
113
|
}
|
|
131
114
|
onUpdate(message);
|
|
@@ -476,7 +459,7 @@ function useKeyExchangeServer(onEvent) {
|
|
|
476
459
|
});
|
|
477
460
|
};
|
|
478
461
|
const completeSetupSuccess = async () => {
|
|
479
|
-
console.log("sending
|
|
462
|
+
console.log("sending completion message to client");
|
|
480
463
|
sendResponse({
|
|
481
464
|
to: [client],
|
|
482
465
|
header: "Setup Succeeded",
|
|
@@ -649,8 +632,8 @@ var CoreTransportLogic = class {
|
|
|
649
632
|
await this.presence.connect(topicHash, deviceInfo.id);
|
|
650
633
|
this.presenceConnected = true;
|
|
651
634
|
}
|
|
652
|
-
broadcastClientState(id, state) {
|
|
653
|
-
this.presence.receiveStatusMessage(id, state);
|
|
635
|
+
broadcastClientState(id, state, name, isHeartbeat) {
|
|
636
|
+
this.presence.receiveStatusMessage(id, state, name, isHeartbeat);
|
|
654
637
|
}
|
|
655
638
|
};
|
|
656
639
|
|
|
@@ -703,9 +686,9 @@ var KeyTransportMain = class {
|
|
|
703
686
|
connectPresence = async (topic) => {
|
|
704
687
|
return this.core.connectPresence(topic);
|
|
705
688
|
};
|
|
706
|
-
broadcastClientState = async (id, state) => {
|
|
689
|
+
broadcastClientState = async (id, state, name, isHeartbeat) => {
|
|
707
690
|
this.peers.set(id, state);
|
|
708
|
-
this.core.broadcastClientState(id, state);
|
|
691
|
+
this.core.broadcastClientState(id, state, name, isHeartbeat);
|
|
709
692
|
};
|
|
710
693
|
onClientStateRequest = async (_callback) => {
|
|
711
694
|
};
|
|
@@ -757,8 +740,8 @@ var setupKeyExchangeHandlers = () => {
|
|
|
757
740
|
});
|
|
758
741
|
ipcMain.handle(
|
|
759
742
|
MESSAGES.broadcastClientState,
|
|
760
|
-
async (_event, id, state) => {
|
|
761
|
-
return transport.broadcastClientState(id, state);
|
|
743
|
+
async (_event, id, state, name, isHeartbeat) => {
|
|
744
|
+
return transport.broadcastClientState(id, state, name, isHeartbeat);
|
|
762
745
|
}
|
|
763
746
|
);
|
|
764
747
|
};
|
package/dist/electron-preload.js
CHANGED
|
@@ -97,7 +97,7 @@ var setupKeyExchangePreloadAPI = () => {
|
|
|
97
97
|
getDeviceInfo: () => import_electron.ipcRenderer.invoke(MESSAGES.getDeviceInfo),
|
|
98
98
|
getHostname: () => import_electron.ipcRenderer.invoke(MESSAGES.getHostname),
|
|
99
99
|
connectPresence: (topic) => import_electron.ipcRenderer.invoke(MESSAGES.connectPresence, topic),
|
|
100
|
-
broadcastClientState: (id, state) => import_electron.ipcRenderer.invoke(MESSAGES.broadcastClientState, id, state),
|
|
100
|
+
broadcastClientState: (id, state, name, isHeartbeat) => import_electron.ipcRenderer.invoke(MESSAGES.broadcastClientState, id, state, name, isHeartbeat),
|
|
101
101
|
onClientStateRequest: (callback) => import_electron.ipcRenderer.on(
|
|
102
102
|
MESSAGES.onClientStateRequest,
|
|
103
103
|
(_event) => callback()
|
|
@@ -71,7 +71,7 @@ var setupKeyExchangePreloadAPI = () => {
|
|
|
71
71
|
getDeviceInfo: () => ipcRenderer.invoke(MESSAGES.getDeviceInfo),
|
|
72
72
|
getHostname: () => ipcRenderer.invoke(MESSAGES.getHostname),
|
|
73
73
|
connectPresence: (topic) => ipcRenderer.invoke(MESSAGES.connectPresence, topic),
|
|
74
|
-
broadcastClientState: (id, state) => ipcRenderer.invoke(MESSAGES.broadcastClientState, id, state),
|
|
74
|
+
broadcastClientState: (id, state, name, isHeartbeat) => ipcRenderer.invoke(MESSAGES.broadcastClientState, id, state, name, isHeartbeat),
|
|
75
75
|
onClientStateRequest: (callback) => ipcRenderer.on(
|
|
76
76
|
MESSAGES.onClientStateRequest,
|
|
77
77
|
(_event) => callback()
|
|
@@ -25,7 +25,7 @@ interface KeyExchangeElectronAPI {
|
|
|
25
25
|
getDeviceInfo: () => Promise<Record<string, any>>;
|
|
26
26
|
getHostname: () => Promise<string>;
|
|
27
27
|
connectPresence: (topic: string) => Promise<void>;
|
|
28
|
-
broadcastClientState: (id: string, state: ClientConnectionState) => Promise<void>;
|
|
28
|
+
broadcastClientState: (id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean) => Promise<void>;
|
|
29
29
|
onClientStateRequest: (callback: () => void) => Promise<() => void>;
|
|
30
30
|
onClientStateUpdate: (callback: (response: {
|
|
31
31
|
id: string;
|
|
@@ -61,7 +61,7 @@ declare class KeyTransportRenderer implements KeyTransportAdapter {
|
|
|
61
61
|
getDeviceInfo: () => Promise<Record<string, any>>;
|
|
62
62
|
getHostname: () => Promise<string>;
|
|
63
63
|
connectPresence: (topic: string) => Promise<void>;
|
|
64
|
-
broadcastClientState: (id: string, state: ClientConnectionState) => Promise<void>;
|
|
64
|
+
broadcastClientState: (id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean) => Promise<void>;
|
|
65
65
|
onClientStateRequest: (callback: () => void) => Promise<() => void>;
|
|
66
66
|
onClientStateUpdate: (callback: (response: {
|
|
67
67
|
id: string;
|
|
@@ -25,7 +25,7 @@ interface KeyExchangeElectronAPI {
|
|
|
25
25
|
getDeviceInfo: () => Promise<Record<string, any>>;
|
|
26
26
|
getHostname: () => Promise<string>;
|
|
27
27
|
connectPresence: (topic: string) => Promise<void>;
|
|
28
|
-
broadcastClientState: (id: string, state: ClientConnectionState) => Promise<void>;
|
|
28
|
+
broadcastClientState: (id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean) => Promise<void>;
|
|
29
29
|
onClientStateRequest: (callback: () => void) => Promise<() => void>;
|
|
30
30
|
onClientStateUpdate: (callback: (response: {
|
|
31
31
|
id: string;
|
|
@@ -61,7 +61,7 @@ declare class KeyTransportRenderer implements KeyTransportAdapter {
|
|
|
61
61
|
getDeviceInfo: () => Promise<Record<string, any>>;
|
|
62
62
|
getHostname: () => Promise<string>;
|
|
63
63
|
connectPresence: (topic: string) => Promise<void>;
|
|
64
|
-
broadcastClientState: (id: string, state: ClientConnectionState) => Promise<void>;
|
|
64
|
+
broadcastClientState: (id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean) => Promise<void>;
|
|
65
65
|
onClientStateRequest: (callback: () => void) => Promise<() => void>;
|
|
66
66
|
onClientStateUpdate: (callback: (response: {
|
|
67
67
|
id: string;
|
|
@@ -81,8 +81,8 @@ var KeyTransportRenderer = class {
|
|
|
81
81
|
connectPresence = async (topic) => {
|
|
82
82
|
return window.keyExchangeElectronAPI.connectPresence(topic);
|
|
83
83
|
};
|
|
84
|
-
broadcastClientState = async (id, state) => {
|
|
85
|
-
return window.keyExchangeElectronAPI.broadcastClientState(id, state);
|
|
84
|
+
broadcastClientState = async (id, state, name, isHeartbeat) => {
|
|
85
|
+
return window.keyExchangeElectronAPI.broadcastClientState(id, state, name, isHeartbeat);
|
|
86
86
|
};
|
|
87
87
|
onClientStateRequest = async (callback) => {
|
|
88
88
|
return window.keyExchangeElectronAPI.onClientStateRequest(callback);
|
|
@@ -54,8 +54,8 @@ var KeyTransportRenderer = class {
|
|
|
54
54
|
connectPresence = async (topic) => {
|
|
55
55
|
return window.keyExchangeElectronAPI.connectPresence(topic);
|
|
56
56
|
};
|
|
57
|
-
broadcastClientState = async (id, state) => {
|
|
58
|
-
return window.keyExchangeElectronAPI.broadcastClientState(id, state);
|
|
57
|
+
broadcastClientState = async (id, state, name, isHeartbeat) => {
|
|
58
|
+
return window.keyExchangeElectronAPI.broadcastClientState(id, state, name, isHeartbeat);
|
|
59
59
|
};
|
|
60
60
|
onClientStateRequest = async (callback) => {
|
|
61
61
|
return window.keyExchangeElectronAPI.onClientStateRequest(callback);
|
package/dist/index.d.mts
CHANGED
|
@@ -40,7 +40,7 @@ declare class KeyTransportClient implements KeyTransportAdapter {
|
|
|
40
40
|
getDeviceInfo: () => Promise<Record<string, any>>;
|
|
41
41
|
getHostname: () => Promise<string>;
|
|
42
42
|
connectPresence: (topic: string) => Promise<void>;
|
|
43
|
-
broadcastClientState: (id: string, state: ClientConnectionState) => Promise<void>;
|
|
43
|
+
broadcastClientState: (id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean) => Promise<void>;
|
|
44
44
|
onClientStateRequest: (callback: () => void) => Promise<() => void>;
|
|
45
45
|
onClientStateUpdate: (callback: (response: {
|
|
46
46
|
id: string;
|
|
@@ -62,4 +62,48 @@ declare class KeyTransportClient implements KeyTransportAdapter {
|
|
|
62
62
|
isConnected: () => boolean;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Manages linked devices (devices that have completed key exchange)
|
|
67
|
+
* Stores device info in localStorage scoped per app
|
|
68
|
+
*/
|
|
69
|
+
interface LinkedDevice {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
customName?: string;
|
|
73
|
+
linkedAt: number;
|
|
74
|
+
}
|
|
75
|
+
declare class DevicePairingManager {
|
|
76
|
+
private storageKey;
|
|
77
|
+
constructor(identityId: string);
|
|
78
|
+
/**
|
|
79
|
+
* Get all linked devices for this app
|
|
80
|
+
*/
|
|
81
|
+
getLinkedDevices: () => LinkedDevice[];
|
|
82
|
+
/**
|
|
83
|
+
* Add a device to the linked devices list
|
|
84
|
+
* Called after successful key exchange
|
|
85
|
+
*/
|
|
86
|
+
addLinkedDevice: (device: {
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
}) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Remove a device from the linked devices list
|
|
92
|
+
* For future use when user wants to unlink a device
|
|
93
|
+
*/
|
|
94
|
+
removeLinkedDevice: (id: string) => void;
|
|
95
|
+
/**
|
|
96
|
+
* Update the hostname of a device (system-level name)
|
|
97
|
+
*/
|
|
98
|
+
updateDeviceName: (id: string, name: string) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Set a custom user-defined name for a device
|
|
101
|
+
*/
|
|
102
|
+
setCustomName: (id: string, customName: string) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Check if a device is linked
|
|
105
|
+
*/
|
|
106
|
+
isLinked: (id: string) => boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { DevicePairingManager, KeyTransportClient, type LinkedDevice };
|
package/dist/index.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ declare class KeyTransportClient implements KeyTransportAdapter {
|
|
|
40
40
|
getDeviceInfo: () => Promise<Record<string, any>>;
|
|
41
41
|
getHostname: () => Promise<string>;
|
|
42
42
|
connectPresence: (topic: string) => Promise<void>;
|
|
43
|
-
broadcastClientState: (id: string, state: ClientConnectionState) => Promise<void>;
|
|
43
|
+
broadcastClientState: (id: string, state: ClientConnectionState, name?: string, isHeartbeat?: boolean) => Promise<void>;
|
|
44
44
|
onClientStateRequest: (callback: () => void) => Promise<() => void>;
|
|
45
45
|
onClientStateUpdate: (callback: (response: {
|
|
46
46
|
id: string;
|
|
@@ -62,4 +62,48 @@ declare class KeyTransportClient implements KeyTransportAdapter {
|
|
|
62
62
|
isConnected: () => boolean;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Manages linked devices (devices that have completed key exchange)
|
|
67
|
+
* Stores device info in localStorage scoped per app
|
|
68
|
+
*/
|
|
69
|
+
interface LinkedDevice {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
customName?: string;
|
|
73
|
+
linkedAt: number;
|
|
74
|
+
}
|
|
75
|
+
declare class DevicePairingManager {
|
|
76
|
+
private storageKey;
|
|
77
|
+
constructor(identityId: string);
|
|
78
|
+
/**
|
|
79
|
+
* Get all linked devices for this app
|
|
80
|
+
*/
|
|
81
|
+
getLinkedDevices: () => LinkedDevice[];
|
|
82
|
+
/**
|
|
83
|
+
* Add a device to the linked devices list
|
|
84
|
+
* Called after successful key exchange
|
|
85
|
+
*/
|
|
86
|
+
addLinkedDevice: (device: {
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
}) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Remove a device from the linked devices list
|
|
92
|
+
* For future use when user wants to unlink a device
|
|
93
|
+
*/
|
|
94
|
+
removeLinkedDevice: (id: string) => void;
|
|
95
|
+
/**
|
|
96
|
+
* Update the hostname of a device (system-level name)
|
|
97
|
+
*/
|
|
98
|
+
updateDeviceName: (id: string, name: string) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Set a custom user-defined name for a device
|
|
101
|
+
*/
|
|
102
|
+
setCustomName: (id: string, customName: string) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Check if a device is linked
|
|
105
|
+
*/
|
|
106
|
+
isLinked: (id: string) => boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { DevicePairingManager, KeyTransportClient, type LinkedDevice };
|
package/dist/index.js
CHANGED
|
@@ -195,6 +195,7 @@ var require_eventemitter3 = __commonJS({
|
|
|
195
195
|
// src/index.ts
|
|
196
196
|
var index_exports = {};
|
|
197
197
|
__export(index_exports, {
|
|
198
|
+
DevicePairingManager: () => DevicePairingManager,
|
|
198
199
|
KeyTransportClient: () => KeyTransportClient
|
|
199
200
|
});
|
|
200
201
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -508,11 +509,11 @@ var KeyTransportClient = class {
|
|
|
508
509
|
throw error;
|
|
509
510
|
}
|
|
510
511
|
};
|
|
511
|
-
broadcastClientState = async (id, state) => {
|
|
512
|
+
broadcastClientState = async (id, state, name, isHeartbeat) => {
|
|
512
513
|
console.log("KeyTransportClient.broadcastClientState");
|
|
513
514
|
this.peers.set(id, state);
|
|
514
515
|
try {
|
|
515
|
-
await this.sendRequest(MESSAGES.broadcastClientState, { id, state });
|
|
516
|
+
await this.sendRequest(MESSAGES.broadcastClientState, { id, state, name, isHeartbeat });
|
|
516
517
|
} catch (error) {
|
|
517
518
|
console.error("Failed to broadcast client state:", error);
|
|
518
519
|
throw error;
|
|
@@ -580,7 +581,99 @@ var KeyTransportClient = class {
|
|
|
580
581
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
581
582
|
};
|
|
582
583
|
};
|
|
584
|
+
|
|
585
|
+
// src/devicePairing.ts
|
|
586
|
+
var DevicePairingManager = class {
|
|
587
|
+
storageKey;
|
|
588
|
+
constructor(identityId) {
|
|
589
|
+
this.storageKey = `cryptforge:identity:${identityId}:linked-devices`;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Get all linked devices for this app
|
|
593
|
+
*/
|
|
594
|
+
getLinkedDevices = () => {
|
|
595
|
+
try {
|
|
596
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
597
|
+
return stored ? JSON.parse(stored) : [];
|
|
598
|
+
} catch (error) {
|
|
599
|
+
console.error("Failed to load linked devices:", error);
|
|
600
|
+
return [];
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
/**
|
|
604
|
+
* Add a device to the linked devices list
|
|
605
|
+
* Called after successful key exchange
|
|
606
|
+
*/
|
|
607
|
+
addLinkedDevice = (device) => {
|
|
608
|
+
try {
|
|
609
|
+
const devices = this.getLinkedDevices();
|
|
610
|
+
const existing = devices.find((d) => d.id === device.id);
|
|
611
|
+
if (existing) {
|
|
612
|
+
existing.name = device.name;
|
|
613
|
+
} else {
|
|
614
|
+
devices.push({
|
|
615
|
+
id: device.id,
|
|
616
|
+
name: device.name,
|
|
617
|
+
linkedAt: Date.now()
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
621
|
+
} catch (error) {
|
|
622
|
+
console.error("Failed to add linked device:", error);
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
/**
|
|
626
|
+
* Remove a device from the linked devices list
|
|
627
|
+
* For future use when user wants to unlink a device
|
|
628
|
+
*/
|
|
629
|
+
removeLinkedDevice = (id) => {
|
|
630
|
+
try {
|
|
631
|
+
const devices = this.getLinkedDevices().filter((d) => d.id !== id);
|
|
632
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
633
|
+
console.log(`Removed linked device: ${id}`);
|
|
634
|
+
} catch (error) {
|
|
635
|
+
console.error("Failed to remove linked device:", error);
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
/**
|
|
639
|
+
* Update the hostname of a device (system-level name)
|
|
640
|
+
*/
|
|
641
|
+
updateDeviceName = (id, name) => {
|
|
642
|
+
try {
|
|
643
|
+
const devices = this.getLinkedDevices();
|
|
644
|
+
const device = devices.find((d) => d.id === id);
|
|
645
|
+
if (device) {
|
|
646
|
+
device.name = name;
|
|
647
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
648
|
+
}
|
|
649
|
+
} catch (error) {
|
|
650
|
+
console.error("Failed to update device name:", error);
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
/**
|
|
654
|
+
* Set a custom user-defined name for a device
|
|
655
|
+
*/
|
|
656
|
+
setCustomName = (id, customName) => {
|
|
657
|
+
try {
|
|
658
|
+
const devices = this.getLinkedDevices();
|
|
659
|
+
const device = devices.find((d) => d.id === id);
|
|
660
|
+
if (device) {
|
|
661
|
+
device.customName = customName.trim() || void 0;
|
|
662
|
+
localStorage.setItem(this.storageKey, JSON.stringify(devices));
|
|
663
|
+
}
|
|
664
|
+
} catch (error) {
|
|
665
|
+
console.error("Failed to set custom device name:", error);
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
/**
|
|
669
|
+
* Check if a device is linked
|
|
670
|
+
*/
|
|
671
|
+
isLinked = (id) => {
|
|
672
|
+
return this.getLinkedDevices().some((d) => d.id === id);
|
|
673
|
+
};
|
|
674
|
+
};
|
|
583
675
|
// Annotate the CommonJS export names for ESM import in node:
|
|
584
676
|
0 && (module.exports = {
|
|
677
|
+
DevicePairingManager,
|
|
585
678
|
KeyTransportClient
|
|
586
679
|
});
|