@agentvault/secure-channel 0.1.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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=crypto-helpers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-helpers.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/crypto-helpers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,73 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-helpers.test.js","sourceRoot":"","sources":["../../src/__tests__/crypto-helpers.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/state.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.test.js","sourceRoot":"","sources":["../../src/__tests__/state.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transport.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/transport.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.test.js","sourceRoot":"","sources":["../../src/__tests__/transport.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { SecureChannelConfig, ChannelState } from "./types.js";
3
+ export declare class SecureChannel extends EventEmitter {
4
+ private config;
5
+ private _state;
6
+ private _deviceId;
7
+ private _fingerprint;
8
+ private _conversationId;
9
+ private _deviceJwt;
10
+ private _ratchet;
11
+ private _ws;
12
+ private _pollTimer;
13
+ private _reconnectAttempt;
14
+ private _reconnectTimer;
15
+ private _stopped;
16
+ private _persisted;
17
+ constructor(config: SecureChannelConfig);
18
+ get state(): ChannelState;
19
+ get deviceId(): string | null;
20
+ get fingerprint(): string | null;
21
+ get conversationId(): string | null;
22
+ start(): Promise<void>;
23
+ send(plaintext: string): Promise<void>;
24
+ stop(): Promise<void>;
25
+ private _enroll;
26
+ private _poll;
27
+ private _activate;
28
+ private _connect;
29
+ private _syncMissedMessages;
30
+ private _scheduleReconnect;
31
+ private _setState;
32
+ private _handleError;
33
+ private _persistState;
34
+ }
35
+ //# sourceMappingURL=channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAY3C,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EAGb,MAAM,YAAY,CAAC;AAkBpB,qBAAa,aAAc,SAAQ,YAAY;IAcjC,OAAO,CAAC,MAAM;IAb1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAA8C;IACrE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAA+B;gBAE7B,MAAM,EAAE,mBAAmB;IAI/C,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAElC;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBtB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBtC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAoBb,OAAO;IA+CrB,OAAO,CAAC,KAAK;YAgCC,SAAS;IAgDvB,OAAO,CAAC,QAAQ;YAgFF,mBAAmB;IAuDjC,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,YAAY;YAKN,aAAa;CAK5B"}
@@ -0,0 +1,325 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { EncryptedMessage } from "@agentvault/crypto";
2
+ export declare function hexToBytes(hex: string): Uint8Array;
3
+ export declare function bytesToHex(bytes: Uint8Array): string;
4
+ export declare function base64ToBytes(b64: string): Uint8Array;
5
+ export declare function bytesToBase64(bytes: Uint8Array): string;
6
+ export interface TransportMessage {
7
+ header_blob: string;
8
+ ciphertext: string;
9
+ }
10
+ export declare function encryptedMessageToTransport(msg: EncryptedMessage): TransportMessage;
11
+ export declare function transportToEncryptedMessage(transport: TransportMessage): EncryptedMessage;
12
+ //# sourceMappingURL=crypto-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-helpers.d.ts","sourceRoot":"","sources":["../src/crypto-helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAElD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAErD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEvD;AAKD,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,gBAAgB,GACpB,gBAAgB,CAgBlB;AAED,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,gBAAgB,GAC1B,gBAAgB,CAelB"}
@@ -0,0 +1,44 @@
1
+ import sodium from "libsodium-wrappers-sumo";
2
+ // --- Encoding helpers ---
3
+ export function hexToBytes(hex) {
4
+ return sodium.from_hex(hex);
5
+ }
6
+ export function bytesToHex(bytes) {
7
+ return sodium.to_hex(bytes);
8
+ }
9
+ export function base64ToBytes(b64) {
10
+ return sodium.from_base64(b64, sodium.base64_variants.ORIGINAL);
11
+ }
12
+ export function bytesToBase64(bytes) {
13
+ return sodium.to_base64(bytes, sodium.base64_variants.ORIGINAL);
14
+ }
15
+ export function encryptedMessageToTransport(msg) {
16
+ const headerObj = {
17
+ dhPublicKey: bytesToBase64(msg.header.dhPublicKey),
18
+ previousChainLength: msg.header.previousChainLength,
19
+ messageNumber: msg.header.messageNumber,
20
+ headerSignature: bytesToBase64(msg.headerSignature),
21
+ nonce: bytesToBase64(msg.nonce),
22
+ };
23
+ const headerJson = JSON.stringify(headerObj);
24
+ const headerBlob = bytesToBase64(new TextEncoder().encode(headerJson));
25
+ return {
26
+ header_blob: headerBlob,
27
+ ciphertext: bytesToBase64(msg.ciphertext),
28
+ };
29
+ }
30
+ export function transportToEncryptedMessage(transport) {
31
+ const headerJson = new TextDecoder().decode(base64ToBytes(transport.header_blob));
32
+ const headerObj = JSON.parse(headerJson);
33
+ return {
34
+ header: {
35
+ dhPublicKey: base64ToBytes(headerObj.dhPublicKey),
36
+ previousChainLength: headerObj.previousChainLength,
37
+ messageNumber: headerObj.messageNumber,
38
+ },
39
+ headerSignature: base64ToBytes(headerObj.headerSignature),
40
+ nonce: base64ToBytes(headerObj.nonce),
41
+ ciphertext: base64ToBytes(transport.ciphertext),
42
+ };
43
+ }
44
+ //# sourceMappingURL=crypto-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-helpers.js","sourceRoot":"","sources":["../src/crypto-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,yBAAyB,CAAC;AAG7C,2BAA2B;AAE3B,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;AAClE,CAAC;AAUD,MAAM,UAAU,2BAA2B,CACzC,GAAqB;IAErB,MAAM,SAAS,GAAG;QAChB,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;QAClD,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,mBAAmB;QACnD,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,aAAa;QACvC,eAAe,EAAE,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC;QACnD,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;KAChC,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,aAAa,CAC9B,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CACrC,CAAC;IACF,OAAO;QACL,WAAW,EAAE,UAAU;QACvB,UAAU,EAAE,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,SAA2B;IAE3B,MAAM,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CACzC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CACrC,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO;QACL,MAAM,EAAE;YACN,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC;YACjD,mBAAmB,EAAE,SAAS,CAAC,mBAAmB;YAClD,aAAa,EAAE,SAAS,CAAC,aAAa;SACvC;QACD,eAAe,EAAE,aAAa,CAAC,SAAS,CAAC,eAAe,CAAC;QACzD,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC;QACrC,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC;KAChD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { SecureChannel } from "./channel.js";
2
+ export type { SecureChannelConfig, ChannelState, MessageMetadata, PersistedState, } from "./types.js";
3
+ export declare const VERSION = "0.1.0";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,eAAO,MAAM,OAAO,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { SecureChannel } from "./channel.js";
2
+ export const VERSION = "0.1.0";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { PersistedState } from "./types.js";
2
+ export declare function saveState(dataDir: string, state: PersistedState): Promise<void>;
3
+ export declare function loadState(dataDir: string): Promise<PersistedState | null>;
4
+ export declare function clearState(dataDir: string): Promise<void>;
5
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQhC;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/D"}
package/dist/state.js ADDED
@@ -0,0 +1,28 @@
1
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ const STATE_FILE = "secure-channel.json";
4
+ export async function saveState(dataDir, state) {
5
+ await mkdir(dataDir, { recursive: true });
6
+ const filePath = join(dataDir, STATE_FILE);
7
+ await writeFile(filePath, JSON.stringify(state, null, 2), "utf-8");
8
+ }
9
+ export async function loadState(dataDir) {
10
+ const filePath = join(dataDir, STATE_FILE);
11
+ try {
12
+ const raw = await readFile(filePath, "utf-8");
13
+ return JSON.parse(raw);
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ export async function clearState(dataDir) {
20
+ const filePath = join(dataDir, STATE_FILE);
21
+ try {
22
+ await rm(filePath);
23
+ }
24
+ catch {
25
+ // File doesn't exist — nothing to clear
26
+ }
27
+ }
28
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,UAAU,GAAG,qBAAqB,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAe,EACf,KAAqB;IAErB,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC3C,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAe;IAEf,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAe;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ export interface EnrollResponse {
2
+ device_id: string;
3
+ fingerprint: string;
4
+ status: string;
5
+ }
6
+ export interface StatusResponse {
7
+ device_id: string;
8
+ status: string;
9
+ fingerprint: string;
10
+ }
11
+ export interface ActivateResponse {
12
+ device_id: string;
13
+ conversation_id: string;
14
+ status: string;
15
+ device_jwt: string;
16
+ owner_identity_public_key: string;
17
+ owner_ephemeral_public_key: string | null;
18
+ }
19
+ export declare function enrollDevice(apiUrl: string, inviteToken: string, identityPkHex: string, ephemeralPkHex: string, proofHex: string, platform?: string): Promise<EnrollResponse>;
20
+ export declare function pollDeviceStatus(apiUrl: string, deviceId: string): Promise<StatusResponse>;
21
+ export declare function activateDevice(apiUrl: string, deviceId: string): Promise<ActivateResponse>;
22
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB,EAAE,MAAM,CAAC;IAClC,0BAA0B,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC,CAiBzB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAOzB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAW3B"}
@@ -0,0 +1,39 @@
1
+ export async function enrollDevice(apiUrl, inviteToken, identityPkHex, ephemeralPkHex, proofHex, platform) {
2
+ const res = await fetch(`${apiUrl}/api/v1/enroll`, {
3
+ method: "POST",
4
+ headers: { "Content-Type": "application/json" },
5
+ body: JSON.stringify({
6
+ invite_token: inviteToken,
7
+ identity_public_key: identityPkHex,
8
+ ephemeral_public_key: ephemeralPkHex,
9
+ proof_of_possession: proofHex,
10
+ platform: platform ?? "node",
11
+ }),
12
+ });
13
+ if (!res.ok) {
14
+ const detail = await res.text();
15
+ throw new Error(`Enrollment failed (${res.status}): ${detail}`);
16
+ }
17
+ return res.json();
18
+ }
19
+ export async function pollDeviceStatus(apiUrl, deviceId) {
20
+ const res = await fetch(`${apiUrl}/api/v1/devices/${deviceId}/status`);
21
+ if (!res.ok) {
22
+ const detail = await res.text();
23
+ throw new Error(`Status poll failed (${res.status}): ${detail}`);
24
+ }
25
+ return res.json();
26
+ }
27
+ export async function activateDevice(apiUrl, deviceId) {
28
+ const res = await fetch(`${apiUrl}/api/v1/devices/${deviceId}/activate`, {
29
+ method: "POST",
30
+ headers: { "Content-Type": "application/json" },
31
+ body: JSON.stringify({}),
32
+ });
33
+ if (!res.ok) {
34
+ const detail = await res.text();
35
+ throw new Error(`Activation failed (${res.status}): ${detail}`);
36
+ }
37
+ return res.json();
38
+ }
39
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAqBA,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAc,EACd,WAAmB,EACnB,aAAqB,EACrB,cAAsB,EACtB,QAAgB,EAChB,QAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,gBAAgB,EAAE;QACjD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,YAAY,EAAE,WAAW;YACzB,mBAAmB,EAAE,aAAa;YAClC,oBAAoB,EAAE,cAAc;YACpC,mBAAmB,EAAE,QAAQ;YAC7B,QAAQ,EAAE,QAAQ,IAAI,MAAM;SAC7B,CAAC;KACH,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,EACd,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,mBAAmB,QAAQ,SAAS,CAAC,CAAC;IACvE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAc,EACd,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,mBAAmB,QAAQ,WAAW,EAAE;QACvE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,32 @@
1
+ export interface SecureChannelConfig {
2
+ inviteToken: string;
3
+ dataDir: string;
4
+ apiUrl: string;
5
+ agentName?: string;
6
+ platform?: string;
7
+ onMessage?: (plaintext: string, metadata: MessageMetadata) => void;
8
+ onStateChange?: (state: ChannelState) => void;
9
+ }
10
+ export type ChannelState = "idle" | "enrolling" | "polling" | "activating" | "connecting" | "ready" | "disconnected" | "error";
11
+ export interface MessageMetadata {
12
+ messageId: string;
13
+ conversationId: string;
14
+ timestamp: string;
15
+ }
16
+ export interface PersistedState {
17
+ deviceId: string;
18
+ deviceJwt: string;
19
+ conversationId: string;
20
+ identityKeypair: {
21
+ publicKey: string;
22
+ privateKey: string;
23
+ };
24
+ ephemeralKeypair: {
25
+ publicKey: string;
26
+ privateKey: string;
27
+ };
28
+ fingerprint: string;
29
+ ratchetState: string;
30
+ lastMessageTimestamp?: string;
31
+ }
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;IACnE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAED,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,WAAW,GACX,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,OAAO,GACP,cAAc,GACd,OAAO,CAAC;AAEZ,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,gBAAgB,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@agentvault/secure-channel",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "license": "MIT",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "test": "vitest run",
11
+ "test:watch": "vitest"
12
+ },
13
+ "files": ["dist"],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "dependencies": {
18
+ "@agentvault/crypto": "^0.1.0",
19
+ "libsodium-wrappers-sumo": "^0.7.15",
20
+ "ws": "^8.16.0"
21
+ },
22
+ "devDependencies": {
23
+ "typescript": "^5.4.0",
24
+ "vitest": "^2.0.0",
25
+ "@types/ws": "^8.5.10",
26
+ "@types/libsodium-wrappers-sumo": "^0.7.8"
27
+ }
28
+ }