@agentvault/secure-channel 0.1.1 → 0.1.2

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/package.json CHANGED
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "name": "@agentvault/secure-channel",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
7
13
  "license": "MIT",
8
14
  "scripts": {
9
- "build": "tsc",
15
+ "build": "tsc --emitDeclarationOnly && node build.mjs",
10
16
  "test": "vitest run",
11
17
  "test:watch": "vitest"
12
18
  },
@@ -21,14 +27,15 @@
21
27
  "access": "public"
22
28
  },
23
29
  "dependencies": {
24
- "@agentvault/crypto": "^0.1.0",
25
- "libsodium-wrappers-sumo": "^0.7.15",
26
30
  "ws": "^8.16.0"
27
31
  },
28
32
  "devDependencies": {
29
- "typescript": "^5.4.0",
30
- "vitest": "^2.0.0",
33
+ "@agentvault/crypto": "^0.1.0",
34
+ "@types/libsodium-wrappers-sumo": "^0.7.8",
31
35
  "@types/ws": "^8.5.10",
32
- "@types/libsodium-wrappers-sumo": "^0.7.8"
36
+ "esbuild": "^0.27.3",
37
+ "libsodium-wrappers-sumo": "^0.7.15",
38
+ "typescript": "^5.4.0",
39
+ "vitest": "^2.0.0"
33
40
  }
34
41
  }
@@ -1,73 +0,0 @@
1
- import { describe, it, expect, beforeAll } from "vitest";
2
- import sodium from "libsodium-wrappers-sumo";
3
- import { hexToBytes, bytesToHex, base64ToBytes, bytesToBase64, encryptedMessageToTransport, transportToEncryptedMessage, } from "../crypto-helpers.js";
4
- beforeAll(async () => {
5
- await sodium.ready;
6
- });
7
- describe("hex conversion", () => {
8
- it("round-trips hex encoding", () => {
9
- const original = sodium.randombytes_buf(32);
10
- const hex = bytesToHex(original);
11
- const decoded = hexToBytes(hex);
12
- expect(decoded).toEqual(original);
13
- });
14
- it("handles known value", () => {
15
- const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
16
- expect(bytesToHex(bytes)).toBe("deadbeef");
17
- expect(hexToBytes("deadbeef")).toEqual(bytes);
18
- });
19
- });
20
- describe("base64 conversion", () => {
21
- it("round-trips base64 encoding", () => {
22
- const original = sodium.randombytes_buf(48);
23
- const b64 = bytesToBase64(original);
24
- const decoded = base64ToBytes(b64);
25
- expect(decoded).toEqual(original);
26
- });
27
- });
28
- describe("transport format", () => {
29
- it("round-trips EncryptedMessage through transport format", () => {
30
- const msg = {
31
- header: {
32
- dhPublicKey: sodium.randombytes_buf(32),
33
- previousChainLength: 3,
34
- messageNumber: 7,
35
- },
36
- headerSignature: sodium.randombytes_buf(64),
37
- nonce: sodium.randombytes_buf(24),
38
- ciphertext: sodium.randombytes_buf(128),
39
- };
40
- const transport = encryptedMessageToTransport(msg);
41
- const restored = transportToEncryptedMessage(transport);
42
- expect(restored.header.dhPublicKey).toEqual(msg.header.dhPublicKey);
43
- expect(restored.header.previousChainLength).toBe(msg.header.previousChainLength);
44
- expect(restored.header.messageNumber).toBe(msg.header.messageNumber);
45
- expect(restored.headerSignature).toEqual(msg.headerSignature);
46
- expect(restored.nonce).toEqual(msg.nonce);
47
- expect(restored.ciphertext).toEqual(msg.ciphertext);
48
- });
49
- it("produces expected transport structure", () => {
50
- const msg = {
51
- header: {
52
- dhPublicKey: sodium.randombytes_buf(32),
53
- previousChainLength: 0,
54
- messageNumber: 0,
55
- },
56
- headerSignature: sodium.randombytes_buf(64),
57
- nonce: sodium.randombytes_buf(24),
58
- ciphertext: sodium.randombytes_buf(16),
59
- };
60
- const transport = encryptedMessageToTransport(msg);
61
- expect(typeof transport.header_blob).toBe("string");
62
- expect(typeof transport.ciphertext).toBe("string");
63
- // header_blob should be base64-encoded JSON
64
- const headerJson = new TextDecoder().decode(base64ToBytes(transport.header_blob));
65
- const headerObj = JSON.parse(headerJson);
66
- expect(headerObj).toHaveProperty("dhPublicKey");
67
- expect(headerObj).toHaveProperty("previousChainLength");
68
- expect(headerObj).toHaveProperty("messageNumber");
69
- expect(headerObj).toHaveProperty("headerSignature");
70
- expect(headerObj).toHaveProperty("nonce");
71
- });
72
- });
73
- //# sourceMappingURL=crypto-helpers.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"crypto-helpers.test.js","sourceRoot":"","sources":["../../src/__tests__/crypto-helpers.test.ts"],"names":[],"mappings":"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"}
@@ -1,58 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { mkdtemp, rm } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { saveState, loadState, clearState } from "../state.js";
6
- const makeState = () => ({
7
- deviceId: "d1234567-1234-1234-1234-123456789abc",
8
- deviceJwt: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.test.sig",
9
- conversationId: "c1234567-1234-1234-1234-123456789abc",
10
- identityKeypair: {
11
- publicKey: "aabb".repeat(16),
12
- privateKey: "ccdd".repeat(16),
13
- },
14
- ephemeralKeypair: {
15
- publicKey: "eeff".repeat(16),
16
- privateKey: "1122".repeat(16),
17
- },
18
- fingerprint: "aa:bb:cc:dd:ee:ff:00:11",
19
- ratchetState: '{"rootKey":"deadbeef"}',
20
- });
21
- let tempDir;
22
- beforeEach(async () => {
23
- tempDir = await mkdtemp(join(tmpdir(), "av-state-test-"));
24
- });
25
- afterEach(async () => {
26
- await rm(tempDir, { recursive: true, force: true });
27
- });
28
- describe("state persistence", () => {
29
- it("round-trips state through save/load", async () => {
30
- const state = makeState();
31
- await saveState(tempDir, state);
32
- const loaded = await loadState(tempDir);
33
- expect(loaded).toEqual(state);
34
- });
35
- it("returns null for missing state file", async () => {
36
- const loaded = await loadState(tempDir);
37
- expect(loaded).toBeNull();
38
- });
39
- it("clearState removes the state file", async () => {
40
- const state = makeState();
41
- await saveState(tempDir, state);
42
- await clearState(tempDir);
43
- const loaded = await loadState(tempDir);
44
- expect(loaded).toBeNull();
45
- });
46
- it("clearState is safe when file doesn't exist", async () => {
47
- // Should not throw
48
- await clearState(tempDir);
49
- });
50
- it("creates dataDir if it doesn't exist", async () => {
51
- const nestedDir = join(tempDir, "nested", "deep");
52
- const state = makeState();
53
- await saveState(nestedDir, state);
54
- const loaded = await loadState(nestedDir);
55
- expect(loaded).toEqual(state);
56
- });
57
- });
58
- //# sourceMappingURL=state.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"state.test.js","sourceRoot":"","sources":["../../src/__tests__/state.test.ts"],"names":[],"mappings":"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"}
@@ -1,101 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
- import { enrollDevice, pollDeviceStatus, activateDevice, } from "../transport.js";
3
- const mockFetch = vi.fn();
4
- beforeEach(() => {
5
- vi.stubGlobal("fetch", mockFetch);
6
- });
7
- afterEach(() => {
8
- vi.restoreAllMocks();
9
- });
10
- const API = "http://localhost:8000";
11
- describe("enrollDevice", () => {
12
- it("sends correct request and returns response", async () => {
13
- const body = {
14
- device_id: "d1234567-1234-1234-1234-123456789abc",
15
- fingerprint: "aa:bb:cc:dd",
16
- status: "PENDING",
17
- };
18
- mockFetch.mockResolvedValueOnce({
19
- ok: true,
20
- json: async () => body,
21
- });
22
- const result = await enrollDevice(API, "invite-token-123", "aabb".repeat(16), "ccdd".repeat(16), "eeff".repeat(32));
23
- expect(mockFetch).toHaveBeenCalledOnce();
24
- const [url, opts] = mockFetch.mock.calls[0];
25
- expect(url).toBe(`${API}/api/v1/enroll`);
26
- expect(opts.method).toBe("POST");
27
- expect(JSON.parse(opts.body)).toEqual({
28
- invite_token: "invite-token-123",
29
- identity_public_key: "aabb".repeat(16),
30
- ephemeral_public_key: "ccdd".repeat(16),
31
- proof_of_possession: "eeff".repeat(32),
32
- platform: "node",
33
- });
34
- expect(result).toEqual(body);
35
- });
36
- it("throws on non-ok response", async () => {
37
- mockFetch.mockResolvedValueOnce({
38
- ok: false,
39
- status: 400,
40
- text: async () => "Bad request",
41
- });
42
- await expect(enrollDevice(API, "bad", "aa", "bb", "cc")).rejects.toThrow("Enrollment failed (400)");
43
- });
44
- });
45
- describe("pollDeviceStatus", () => {
46
- it("sends GET and returns status", async () => {
47
- const body = {
48
- device_id: "d1234567-1234-1234-1234-123456789abc",
49
- status: "PENDING",
50
- fingerprint: "aa:bb:cc:dd",
51
- };
52
- mockFetch.mockResolvedValueOnce({
53
- ok: true,
54
- json: async () => body,
55
- });
56
- const result = await pollDeviceStatus(API, "d1234567-1234-1234-1234-123456789abc");
57
- expect(mockFetch).toHaveBeenCalledOnce();
58
- const [url] = mockFetch.mock.calls[0];
59
- expect(url).toBe(`${API}/api/v1/devices/d1234567-1234-1234-1234-123456789abc/status`);
60
- expect(result).toEqual(body);
61
- });
62
- it("throws on non-ok response", async () => {
63
- mockFetch.mockResolvedValueOnce({
64
- ok: false,
65
- status: 429,
66
- text: async () => "Rate limited",
67
- });
68
- await expect(pollDeviceStatus(API, "xxx")).rejects.toThrow("Status poll failed (429)");
69
- });
70
- });
71
- describe("activateDevice", () => {
72
- it("sends POST and returns activation data", async () => {
73
- const body = {
74
- device_id: "d1234567-1234-1234-1234-123456789abc",
75
- conversation_id: "c1234567-1234-1234-1234-123456789abc",
76
- status: "ACTIVE",
77
- device_jwt: "eyJ0eXAi.test.sig",
78
- owner_identity_public_key: "aabb".repeat(16),
79
- owner_ephemeral_public_key: "ccdd".repeat(16),
80
- };
81
- mockFetch.mockResolvedValueOnce({
82
- ok: true,
83
- json: async () => body,
84
- });
85
- const result = await activateDevice(API, "d1234567-1234-1234-1234-123456789abc");
86
- expect(mockFetch).toHaveBeenCalledOnce();
87
- const [url, opts] = mockFetch.mock.calls[0];
88
- expect(url).toBe(`${API}/api/v1/devices/d1234567-1234-1234-1234-123456789abc/activate`);
89
- expect(opts.method).toBe("POST");
90
- expect(result).toEqual(body);
91
- });
92
- it("throws on non-ok response", async () => {
93
- mockFetch.mockResolvedValueOnce({
94
- ok: false,
95
- status: 409,
96
- text: async () => "Conflict",
97
- });
98
- await expect(activateDevice(API, "xxx")).rejects.toThrow("Activation failed (409)");
99
- });
100
- });
101
- //# sourceMappingURL=transport.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transport.test.js","sourceRoot":"","sources":["../../src/__tests__/transport.test.ts"],"names":[],"mappings":"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"}
package/dist/channel.js DELETED
@@ -1,325 +0,0 @@
1
- import { EventEmitter } from "node:events";
2
- import sodium from "libsodium-wrappers-sumo";
3
- import WebSocket from "ws";
4
- import { generateIdentityKeypair, generateEphemeralKeypair, computeFingerprint, createProofOfPossession, performX3DH, DoubleRatchet, } from "@agentvault/crypto";
5
- import { hexToBytes, bytesToHex, encryptedMessageToTransport, transportToEncryptedMessage, } from "./crypto-helpers.js";
6
- import { saveState, loadState, clearState } from "./state.js";
7
- import { enrollDevice, pollDeviceStatus, activateDevice, } from "./transport.js";
8
- const POLL_INTERVAL_MS = 5_000;
9
- const RECONNECT_BASE_MS = 1_000;
10
- const RECONNECT_MAX_MS = 30_000;
11
- export class SecureChannel extends EventEmitter {
12
- config;
13
- _state = "idle";
14
- _deviceId = null;
15
- _fingerprint = null;
16
- _conversationId = null;
17
- _deviceJwt = null;
18
- _ratchet = null;
19
- _ws = null;
20
- _pollTimer = null;
21
- _reconnectAttempt = 0;
22
- _reconnectTimer = null;
23
- _stopped = false;
24
- _persisted = null;
25
- constructor(config) {
26
- super();
27
- this.config = config;
28
- }
29
- get state() {
30
- return this._state;
31
- }
32
- get deviceId() {
33
- return this._deviceId;
34
- }
35
- get fingerprint() {
36
- return this._fingerprint;
37
- }
38
- get conversationId() {
39
- return this._conversationId;
40
- }
41
- async start() {
42
- this._stopped = false;
43
- await sodium.ready;
44
- // Check for persisted state
45
- const persisted = await loadState(this.config.dataDir);
46
- if (persisted) {
47
- this._persisted = persisted;
48
- this._deviceId = persisted.deviceId;
49
- this._deviceJwt = persisted.deviceJwt;
50
- this._conversationId = persisted.conversationId;
51
- this._fingerprint = persisted.fingerprint;
52
- this._ratchet = DoubleRatchet.deserialize(persisted.ratchetState);
53
- this._connect();
54
- return;
55
- }
56
- // Full lifecycle: enroll → poll → activate → connect
57
- await this._enroll();
58
- }
59
- async send(plaintext) {
60
- if (this._state !== "ready" || !this._ratchet || !this._ws) {
61
- throw new Error("Channel is not ready");
62
- }
63
- const encrypted = this._ratchet.encrypt(plaintext);
64
- const transport = encryptedMessageToTransport(encrypted);
65
- this._ws.send(JSON.stringify({
66
- event: "message",
67
- data: {
68
- conversation_id: this._conversationId,
69
- header_blob: transport.header_blob,
70
- ciphertext: transport.ciphertext,
71
- },
72
- }));
73
- // Persist ratchet state after encrypt
74
- await this._persistState();
75
- }
76
- async stop() {
77
- this._stopped = true;
78
- if (this._pollTimer) {
79
- clearTimeout(this._pollTimer);
80
- this._pollTimer = null;
81
- }
82
- if (this._reconnectTimer) {
83
- clearTimeout(this._reconnectTimer);
84
- this._reconnectTimer = null;
85
- }
86
- if (this._ws) {
87
- this._ws.removeAllListeners();
88
- this._ws.close();
89
- this._ws = null;
90
- }
91
- this._setState("disconnected");
92
- }
93
- // --- Internal lifecycle ---
94
- async _enroll() {
95
- this._setState("enrolling");
96
- try {
97
- const identity = await generateIdentityKeypair();
98
- const ephemeral = await generateEphemeralKeypair();
99
- const fingerprint = computeFingerprint(identity.publicKey);
100
- const proof = createProofOfPossession(identity.privateKey, identity.publicKey);
101
- const result = await enrollDevice(this.config.apiUrl, this.config.inviteToken, bytesToHex(identity.publicKey), bytesToHex(ephemeral.publicKey), bytesToHex(proof), this.config.platform);
102
- this._deviceId = result.device_id;
103
- this._fingerprint = result.fingerprint;
104
- // Store keypairs temporarily for activation (not persisted yet — no JWT)
105
- this._persisted = {
106
- deviceId: result.device_id,
107
- deviceJwt: "", // set after activation
108
- conversationId: "", // set after activation
109
- identityKeypair: {
110
- publicKey: bytesToHex(identity.publicKey),
111
- privateKey: bytesToHex(identity.privateKey),
112
- },
113
- ephemeralKeypair: {
114
- publicKey: bytesToHex(ephemeral.publicKey),
115
- privateKey: bytesToHex(ephemeral.privateKey),
116
- },
117
- fingerprint: result.fingerprint,
118
- ratchetState: "", // set after activation
119
- };
120
- this._poll();
121
- }
122
- catch (err) {
123
- this._handleError(err);
124
- }
125
- }
126
- _poll() {
127
- if (this._stopped)
128
- return;
129
- this._setState("polling");
130
- const doPoll = async () => {
131
- if (this._stopped)
132
- return;
133
- try {
134
- const status = await pollDeviceStatus(this.config.apiUrl, this._deviceId);
135
- if (status.status === "APPROVED") {
136
- await this._activate();
137
- return;
138
- }
139
- if (status.status === "REVOKED") {
140
- this._handleError(new Error("Device was revoked"));
141
- return;
142
- }
143
- // Still PENDING — poll again
144
- this._pollTimer = setTimeout(doPoll, POLL_INTERVAL_MS);
145
- }
146
- catch (err) {
147
- this._handleError(err);
148
- }
149
- };
150
- this._pollTimer = setTimeout(doPoll, POLL_INTERVAL_MS);
151
- }
152
- async _activate() {
153
- this._setState("activating");
154
- try {
155
- const result = await activateDevice(this.config.apiUrl, this._deviceId);
156
- this._conversationId = result.conversation_id;
157
- this._deviceJwt = result.device_jwt;
158
- // Perform X3DH as receiver (agent side)
159
- const identity = this._persisted.identityKeypair;
160
- const ephemeral = this._persisted.ephemeralKeypair;
161
- const sharedSecret = await performX3DH({
162
- myIdentityPrivate: hexToBytes(identity.privateKey),
163
- myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
164
- theirIdentityPublic: hexToBytes(result.owner_identity_public_key),
165
- theirEphemeralPublic: hexToBytes(result.owner_ephemeral_public_key ?? result.owner_identity_public_key),
166
- isInitiator: false,
167
- });
168
- // Initialize ratchet as receiver
169
- this._ratchet = DoubleRatchet.initReceiver(sharedSecret, {
170
- publicKey: hexToBytes(identity.publicKey),
171
- privateKey: hexToBytes(identity.privateKey),
172
- keyType: "ed25519",
173
- });
174
- // Persist full state
175
- this._persisted = {
176
- ...this._persisted,
177
- deviceJwt: result.device_jwt,
178
- conversationId: result.conversation_id,
179
- ratchetState: this._ratchet.serialize(),
180
- };
181
- await saveState(this.config.dataDir, this._persisted);
182
- this._connect();
183
- }
184
- catch (err) {
185
- this._handleError(err);
186
- }
187
- }
188
- _connect() {
189
- if (this._stopped)
190
- return;
191
- this._setState("connecting");
192
- const wsUrl = this.config.apiUrl.replace(/^http/, "ws");
193
- const url = `${wsUrl}/api/v1/ws?token=${encodeURIComponent(this._deviceJwt)}&device_id=${this._deviceId}`;
194
- const ws = new WebSocket(url);
195
- this._ws = ws;
196
- ws.on("open", async () => {
197
- this._reconnectAttempt = 0;
198
- // Sync missed messages before declaring ready
199
- await this._syncMissedMessages();
200
- this._setState("ready");
201
- this.emit("ready");
202
- });
203
- ws.on("message", async (raw) => {
204
- try {
205
- const data = JSON.parse(raw.toString());
206
- if (data.event === "ping") {
207
- ws.send(JSON.stringify({ event: "pong" }));
208
- return;
209
- }
210
- if (data.event === "device_revoked") {
211
- await clearState(this.config.dataDir);
212
- this._handleError(new Error("Device was revoked"));
213
- return;
214
- }
215
- if (data.event === "message") {
216
- const msgData = data.data;
217
- // Don't decrypt our own messages
218
- if (msgData.sender_device_id === this._deviceId)
219
- return;
220
- const encrypted = transportToEncryptedMessage({
221
- header_blob: msgData.header_blob,
222
- ciphertext: msgData.ciphertext,
223
- });
224
- const plaintext = this._ratchet.decrypt(encrypted);
225
- // Persist ratchet state after decrypt
226
- await this._persistState();
227
- const metadata = {
228
- messageId: msgData.message_id,
229
- conversationId: msgData.conversation_id,
230
- timestamp: msgData.created_at,
231
- };
232
- this.emit("message", plaintext, metadata);
233
- this.config.onMessage?.(plaintext, metadata);
234
- // Track last message timestamp for offline sync
235
- this._persisted.lastMessageTimestamp = msgData.created_at;
236
- }
237
- }
238
- catch (err) {
239
- this.emit("error", err);
240
- }
241
- });
242
- ws.on("close", () => {
243
- if (this._stopped)
244
- return;
245
- this._setState("disconnected");
246
- this._scheduleReconnect();
247
- });
248
- ws.on("error", (err) => {
249
- this.emit("error", err);
250
- // The close event will fire after this and handle reconnection
251
- });
252
- }
253
- async _syncMissedMessages() {
254
- if (!this._persisted?.lastMessageTimestamp || !this._deviceJwt)
255
- return;
256
- try {
257
- const since = encodeURIComponent(this._persisted.lastMessageTimestamp);
258
- const url = `${this.config.apiUrl}/api/v1/devices/${this._deviceId}/messages?since=${since}&limit=200`;
259
- const res = await fetch(url, {
260
- headers: { Authorization: `Bearer ${this._deviceJwt}` },
261
- });
262
- if (!res.ok)
263
- return; // Non-critical — will get new messages via WS
264
- const messages = await res.json();
265
- for (const msg of messages) {
266
- // Skip our own messages
267
- if (msg.sender_device_id === this._deviceId)
268
- continue;
269
- try {
270
- const encrypted = transportToEncryptedMessage({
271
- header_blob: msg.header_blob,
272
- ciphertext: msg.ciphertext,
273
- });
274
- const plaintext = this._ratchet.decrypt(encrypted);
275
- const metadata = {
276
- messageId: msg.id,
277
- conversationId: msg.conversation_id,
278
- timestamp: msg.created_at,
279
- };
280
- this.emit("message", plaintext, metadata);
281
- this.config.onMessage?.(plaintext, metadata);
282
- // Update last message timestamp
283
- this._persisted.lastMessageTimestamp = msg.created_at;
284
- }
285
- catch (err) {
286
- this.emit("error", err);
287
- break; // Ratchet desync — stop processing
288
- }
289
- }
290
- await this._persistState();
291
- }
292
- catch {
293
- // Network error — non-critical, will get messages via WS
294
- }
295
- }
296
- _scheduleReconnect() {
297
- if (this._stopped)
298
- return;
299
- const delay = Math.min(RECONNECT_BASE_MS * Math.pow(2, this._reconnectAttempt), RECONNECT_MAX_MS);
300
- this._reconnectAttempt++;
301
- this._reconnectTimer = setTimeout(() => {
302
- if (!this._stopped) {
303
- this._connect();
304
- }
305
- }, delay);
306
- }
307
- _setState(newState) {
308
- if (this._state === newState)
309
- return;
310
- this._state = newState;
311
- this.emit("state", newState);
312
- this.config.onStateChange?.(newState);
313
- }
314
- _handleError(err) {
315
- this._setState("error");
316
- this.emit("error", err);
317
- }
318
- async _persistState() {
319
- if (!this._persisted || !this._ratchet)
320
- return;
321
- this._persisted.ratchetState = this._ratchet.serialize();
322
- await saveState(this.config.dataDir, this._persisted);
323
- }
324
- }
325
- //# sourceMappingURL=channel.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}