happy-coder 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +354 -917
- package/dist/index.mjs +280 -843
- package/dist/install-B2r_gX72.cjs +109 -0
- package/dist/install-HKe7dyS4.mjs +107 -0
- package/dist/lib.cjs +32 -0
- package/dist/lib.d.cts +727 -0
- package/dist/lib.d.mts +727 -0
- package/dist/lib.mjs +14 -0
- package/dist/run-FBXkmmN7.mjs +32 -0
- package/dist/run-q2To6b-c.cjs +34 -0
- package/dist/types-fXgEaaqP.mjs +861 -0
- package/dist/types-mykDX2xe.cjs +872 -0
- package/dist/uninstall-C42CoSCI.cjs +53 -0
- package/dist/uninstall-CLkTtlMv.mjs +51 -0
- package/package.json +25 -10
- package/dist/auth/auth.d.ts +0 -38
- package/dist/auth/auth.js +0 -76
- package/dist/auth/auth.test.d.ts +0 -7
- package/dist/auth/auth.test.js +0 -96
- package/dist/auth/crypto.d.ts +0 -25
- package/dist/auth/crypto.js +0 -36
- package/dist/claude/claude.d.ts +0 -54
- package/dist/claude/claude.js +0 -170
- package/dist/claude/claude.test.d.ts +0 -7
- package/dist/claude/claude.test.js +0 -130
- package/dist/claude/types.d.ts +0 -37
- package/dist/claude/types.js +0 -7
- package/dist/commands/start.d.ts +0 -38
- package/dist/commands/start.js +0 -161
- package/dist/commands/start.test.d.ts +0 -7
- package/dist/commands/start.test.js +0 -307
- package/dist/handlers/message-handler.d.ts +0 -65
- package/dist/handlers/message-handler.js +0 -187
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/session/service.d.ts +0 -27
- package/dist/session/service.js +0 -93
- package/dist/session/service.test.d.ts +0 -7
- package/dist/session/service.test.js +0 -71
- package/dist/session/types.d.ts +0 -44
- package/dist/session/types.js +0 -4
- package/dist/socket/client.d.ts +0 -50
- package/dist/socket/client.js +0 -136
- package/dist/socket/client.test.d.ts +0 -7
- package/dist/socket/client.test.js +0 -74
- package/dist/socket/types.d.ts +0 -80
- package/dist/socket/types.js +0 -12
- package/dist/utils/config.d.ts +0 -22
- package/dist/utils/config.js +0 -23
- package/dist/utils/logger.d.ts +0 -26
- package/dist/utils/logger.js +0 -60
- package/dist/utils/paths.d.ts +0 -18
- package/dist/utils/paths.js +0 -24
- package/dist/utils/qrcode.d.ts +0 -19
- package/dist/utils/qrcode.js +0 -37
- package/dist/utils/qrcode.test.d.ts +0 -7
- package/dist/utils/qrcode.test.js +0 -14
package/dist/session/service.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session service for managing handy-server sessions
|
|
3
|
-
*/
|
|
4
|
-
import { logger } from '#utils/logger';
|
|
5
|
-
import axios from 'axios';
|
|
6
|
-
export class SessionService {
|
|
7
|
-
serverUrl;
|
|
8
|
-
authToken;
|
|
9
|
-
constructor(serverUrl, authToken) {
|
|
10
|
-
this.serverUrl = serverUrl;
|
|
11
|
-
this.authToken = authToken;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Create a new session or load existing one with the given tag
|
|
15
|
-
*/
|
|
16
|
-
async createSession(tag) {
|
|
17
|
-
try {
|
|
18
|
-
const response = await axios.post(`${this.serverUrl}/v1/sessions`, { tag }, {
|
|
19
|
-
headers: {
|
|
20
|
-
'Authorization': `Bearer ${this.authToken}`,
|
|
21
|
-
'Content-Type': 'application/json'
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
logger.info(`Session created/loaded: ${response.data.session.id} (tag: ${tag})`);
|
|
25
|
-
return response.data;
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
logger.error('Failed to create session:', error);
|
|
29
|
-
throw new Error(`Failed to create session: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Decrypt a message content
|
|
34
|
-
* Note: In real implementation, this would use proper decryption
|
|
35
|
-
*/
|
|
36
|
-
decryptContent(encryptedContent) {
|
|
37
|
-
try {
|
|
38
|
-
const jsonContent = Buffer.from(encryptedContent, 'base64').toString('utf8');
|
|
39
|
-
return JSON.parse(jsonContent);
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
logger.error('Failed to decrypt content:', error);
|
|
43
|
-
throw new Error('Failed to decrypt message content');
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Get messages from a session
|
|
48
|
-
*/
|
|
49
|
-
async getMessages(sessionId) {
|
|
50
|
-
try {
|
|
51
|
-
const response = await axios.get(`${this.serverUrl}/v1/sessions/${sessionId}/messages`, {
|
|
52
|
-
headers: {
|
|
53
|
-
'Authorization': `Bearer ${this.authToken}`,
|
|
54
|
-
'Content-Type': 'application/json'
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
logger.debug(`Retrieved ${response.data.messages.length} messages from session ${sessionId}`);
|
|
58
|
-
return response.data;
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
logger.error('Failed to get messages:', error);
|
|
62
|
-
throw new Error(`Failed to get messages: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Send a message to a session
|
|
67
|
-
* Note: In real implementation, we'd encrypt the content before sending
|
|
68
|
-
*/
|
|
69
|
-
async sendMessage(sessionId, content) {
|
|
70
|
-
try {
|
|
71
|
-
// For now, we'll just base64 encode the JSON content
|
|
72
|
-
// In production, this should use proper encryption
|
|
73
|
-
const jsonContent = JSON.stringify(content);
|
|
74
|
-
const base64Content = Buffer.from(jsonContent).toString('base64');
|
|
75
|
-
const messageContent = {
|
|
76
|
-
c: base64Content,
|
|
77
|
-
t: 'encrypted'
|
|
78
|
-
};
|
|
79
|
-
const response = await axios.post(`${this.serverUrl}/v1/sessions/${sessionId}/messages`, messageContent, {
|
|
80
|
-
headers: {
|
|
81
|
-
'Authorization': `Bearer ${this.authToken}`,
|
|
82
|
-
'Content-Type': 'application/json'
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
logger.debug(`Message sent to session ${sessionId}, seq: ${response.data.message.seq}`);
|
|
86
|
-
return response.data;
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
logger.error('Failed to send message:', error);
|
|
90
|
-
throw new Error(`Failed to send message: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for the session service module
|
|
3
|
-
*
|
|
4
|
-
* This test verifies the complete session workflow: create session, send message, read message
|
|
5
|
-
* using the real handy server API. No mocking is used as per project requirements.
|
|
6
|
-
*/
|
|
7
|
-
import { authGetToken, getOrCreateSecretKey } from '#auth/auth';
|
|
8
|
-
import { getConfig } from '#utils/config';
|
|
9
|
-
import { expect } from 'chai';
|
|
10
|
-
import { SessionService } from './service.js';
|
|
11
|
-
describe('SessionService', () => {
|
|
12
|
-
let sessionService;
|
|
13
|
-
let authToken;
|
|
14
|
-
before(async () => {
|
|
15
|
-
// Get auth token for tests
|
|
16
|
-
const config = getConfig();
|
|
17
|
-
const secret = await getOrCreateSecretKey();
|
|
18
|
-
authToken = await authGetToken(config.serverUrl, secret);
|
|
19
|
-
// Create session service instance
|
|
20
|
-
sessionService = new SessionService(config.serverUrl, authToken);
|
|
21
|
-
});
|
|
22
|
-
it('should create session, send message, and read message back', async () => {
|
|
23
|
-
// 1. Create a session
|
|
24
|
-
const tag = `test-session-${Date.now()}`;
|
|
25
|
-
const sessionResponse = await sessionService.createSession(tag);
|
|
26
|
-
expect(sessionResponse).to.be.an('object');
|
|
27
|
-
expect(sessionResponse.session).to.be.an('object');
|
|
28
|
-
expect(sessionResponse.session.id).to.be.a('string');
|
|
29
|
-
expect(sessionResponse.session.tag).to.equal(tag);
|
|
30
|
-
expect(sessionResponse.session.seq).to.be.a('number');
|
|
31
|
-
expect(sessionResponse.session.createdAt).to.be.a('number');
|
|
32
|
-
expect(sessionResponse.session.updatedAt).to.be.a('number');
|
|
33
|
-
const sessionId = sessionResponse.session.id;
|
|
34
|
-
// 2. Send a message to the session
|
|
35
|
-
const messageContent = {
|
|
36
|
-
content: 'Hello, this is a test message from the session service test',
|
|
37
|
-
type: 'text-input'
|
|
38
|
-
};
|
|
39
|
-
const sendResponse = await sessionService.sendMessage(sessionId, messageContent);
|
|
40
|
-
expect(sendResponse).to.be.an('object');
|
|
41
|
-
expect(sendResponse.message).to.be.an('object');
|
|
42
|
-
expect(sendResponse.message.id).to.be.a('string');
|
|
43
|
-
expect(sendResponse.message.seq).to.be.a('number');
|
|
44
|
-
expect(sendResponse.message.content).to.be.an('object');
|
|
45
|
-
expect(sendResponse.message.content.c).to.be.a('string');
|
|
46
|
-
expect(sendResponse.message.content.t).to.equal('encrypted');
|
|
47
|
-
expect(sendResponse.message.createdAt).to.be.a('number');
|
|
48
|
-
expect(sendResponse.message.updatedAt).to.be.a('number');
|
|
49
|
-
// 3. Read messages from the session
|
|
50
|
-
const getResponse = await sessionService.getMessages(sessionId);
|
|
51
|
-
expect(getResponse).to.be.an('object');
|
|
52
|
-
expect(getResponse.messages).to.be.an('array');
|
|
53
|
-
expect(getResponse.messages.length).to.be.greaterThan(0);
|
|
54
|
-
// Find our message (should be the first one since it's ordered by createdAt desc)
|
|
55
|
-
const retrievedMessage = getResponse.messages[0];
|
|
56
|
-
expect(retrievedMessage).to.be.an('object');
|
|
57
|
-
expect(retrievedMessage.id).to.equal(sendResponse.message.id);
|
|
58
|
-
expect(retrievedMessage.seq).to.equal(sendResponse.message.seq);
|
|
59
|
-
expect(retrievedMessage.content).to.be.an('object');
|
|
60
|
-
expect(retrievedMessage.content.c).to.equal(sendResponse.message.content.c);
|
|
61
|
-
expect(retrievedMessage.content.t).to.equal('encrypted');
|
|
62
|
-
// 4. Decrypt the retrieved message and verify it matches what we sent
|
|
63
|
-
const decryptedContent = sessionService.decryptContent(retrievedMessage.content.c);
|
|
64
|
-
expect(decryptedContent).to.deep.equal(messageContent);
|
|
65
|
-
console.log('✅ Complete workflow test passed:');
|
|
66
|
-
console.log(` - Created session: ${sessionId}`);
|
|
67
|
-
console.log(` - Sent message with seq: ${sendResponse.message.seq}`);
|
|
68
|
-
console.log(` - Retrieved ${getResponse.messages.length} messages`);
|
|
69
|
-
console.log(` - Decrypted content matches original: ${JSON.stringify(messageContent)}`);
|
|
70
|
-
});
|
|
71
|
-
});
|
package/dist/session/types.d.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session types for handy-server integration
|
|
3
|
-
*/
|
|
4
|
-
export interface Session {
|
|
5
|
-
createdAt: number;
|
|
6
|
-
id: string;
|
|
7
|
-
seq: number;
|
|
8
|
-
tag: string;
|
|
9
|
-
updatedAt: number;
|
|
10
|
-
}
|
|
11
|
-
export interface SessionMessage {
|
|
12
|
-
content: MessageContent;
|
|
13
|
-
createdAt: number;
|
|
14
|
-
id: string;
|
|
15
|
-
seq: number;
|
|
16
|
-
updatedAt: number;
|
|
17
|
-
}
|
|
18
|
-
export interface MessageContent {
|
|
19
|
-
c: string;
|
|
20
|
-
t: 'encrypted';
|
|
21
|
-
}
|
|
22
|
-
export interface CreateSessionResponse {
|
|
23
|
-
session: Session;
|
|
24
|
-
}
|
|
25
|
-
export interface SendMessageResponse {
|
|
26
|
-
message: SessionMessage;
|
|
27
|
-
}
|
|
28
|
-
export interface ListSessionsResponse {
|
|
29
|
-
sessions: Session[];
|
|
30
|
-
}
|
|
31
|
-
export interface GetMessagesResponse {
|
|
32
|
-
messages: SessionMessage[];
|
|
33
|
-
}
|
|
34
|
-
export interface SocketUpdate {
|
|
35
|
-
content: {
|
|
36
|
-
c: string;
|
|
37
|
-
mid: string;
|
|
38
|
-
sid: string;
|
|
39
|
-
t: 'new-message';
|
|
40
|
-
};
|
|
41
|
-
createdAt: number;
|
|
42
|
-
id: string;
|
|
43
|
-
seq: number;
|
|
44
|
-
}
|
package/dist/session/types.js
DELETED
package/dist/socket/client.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Socket.IO client for handy-cli
|
|
3
|
-
*
|
|
4
|
-
* This module manages the WebSocket connection to the handy server.
|
|
5
|
-
* It handles authentication, connection lifecycle, and message routing.
|
|
6
|
-
*
|
|
7
|
-
* Key responsibilities:
|
|
8
|
-
* - Establish authenticated socket connection
|
|
9
|
-
* - Handle reconnection logic
|
|
10
|
-
* - Route messages between server and local handlers
|
|
11
|
-
* - Manage connection state
|
|
12
|
-
*
|
|
13
|
-
* Design decisions:
|
|
14
|
-
* - Uses socket.io-client for compatibility with server
|
|
15
|
-
* - Auth token passed in handshake for authentication
|
|
16
|
-
* - Automatic reconnection with exponential backoff
|
|
17
|
-
* - Event emitter pattern for decoupled message handling
|
|
18
|
-
*/
|
|
19
|
-
import { EventEmitter } from 'node:events';
|
|
20
|
-
export interface SocketClientOptions {
|
|
21
|
-
authToken: string;
|
|
22
|
-
serverUrl: string;
|
|
23
|
-
socketPath: string;
|
|
24
|
-
}
|
|
25
|
-
export declare class SocketClient extends EventEmitter {
|
|
26
|
-
private isConnected;
|
|
27
|
-
private options;
|
|
28
|
-
private socket;
|
|
29
|
-
constructor(options: SocketClientOptions);
|
|
30
|
-
/**
|
|
31
|
-
* Connect to the socket server
|
|
32
|
-
*/
|
|
33
|
-
connect(): void;
|
|
34
|
-
/**
|
|
35
|
-
* Disconnect from the socket server
|
|
36
|
-
*/
|
|
37
|
-
disconnect(): void;
|
|
38
|
-
/**
|
|
39
|
-
* Check if socket is connected
|
|
40
|
-
*/
|
|
41
|
-
getIsConnected(): boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Wait for socket to be authenticated
|
|
44
|
-
*/
|
|
45
|
-
waitForAuth(): Promise<string>;
|
|
46
|
-
/**
|
|
47
|
-
* Set up socket event handlers
|
|
48
|
-
*/
|
|
49
|
-
private setupEventHandlers;
|
|
50
|
-
}
|
package/dist/socket/client.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Socket.IO client for handy-cli
|
|
3
|
-
*
|
|
4
|
-
* This module manages the WebSocket connection to the handy server.
|
|
5
|
-
* It handles authentication, connection lifecycle, and message routing.
|
|
6
|
-
*
|
|
7
|
-
* Key responsibilities:
|
|
8
|
-
* - Establish authenticated socket connection
|
|
9
|
-
* - Handle reconnection logic
|
|
10
|
-
* - Route messages between server and local handlers
|
|
11
|
-
* - Manage connection state
|
|
12
|
-
*
|
|
13
|
-
* Design decisions:
|
|
14
|
-
* - Uses socket.io-client for compatibility with server
|
|
15
|
-
* - Auth token passed in handshake for authentication
|
|
16
|
-
* - Automatic reconnection with exponential backoff
|
|
17
|
-
* - Event emitter pattern for decoupled message handling
|
|
18
|
-
*/
|
|
19
|
-
import { logger } from '#utils/logger';
|
|
20
|
-
import { EventEmitter } from 'node:events';
|
|
21
|
-
import { io } from 'socket.io-client';
|
|
22
|
-
// eslint-disable-next-line unicorn/prefer-event-target
|
|
23
|
-
export class SocketClient extends EventEmitter {
|
|
24
|
-
isConnected = false;
|
|
25
|
-
options;
|
|
26
|
-
socket = null;
|
|
27
|
-
constructor(options) {
|
|
28
|
-
super();
|
|
29
|
-
this.options = options;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Connect to the socket server
|
|
33
|
-
*/
|
|
34
|
-
connect() {
|
|
35
|
-
if (this.socket) {
|
|
36
|
-
logger.warn('Socket already connected');
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
logger.info('Connecting to socket server...');
|
|
40
|
-
logger.debug(`Server URL: ${this.options.serverUrl}`);
|
|
41
|
-
logger.debug(`Socket path: ${this.options.socketPath}`);
|
|
42
|
-
this.socket = io(this.options.serverUrl, {
|
|
43
|
-
auth: {
|
|
44
|
-
token: this.options.authToken
|
|
45
|
-
},
|
|
46
|
-
path: this.options.socketPath,
|
|
47
|
-
reconnection: true,
|
|
48
|
-
reconnectionAttempts: Infinity,
|
|
49
|
-
reconnectionDelay: 1000,
|
|
50
|
-
reconnectionDelayMax: 5000,
|
|
51
|
-
transports: ['websocket', 'polling'],
|
|
52
|
-
withCredentials: true
|
|
53
|
-
});
|
|
54
|
-
this.setupEventHandlers();
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Disconnect from the socket server
|
|
58
|
-
*/
|
|
59
|
-
disconnect() {
|
|
60
|
-
if (this.socket) {
|
|
61
|
-
logger.info('Disconnecting socket...');
|
|
62
|
-
this.socket.disconnect();
|
|
63
|
-
this.socket = null;
|
|
64
|
-
this.isConnected = false;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Check if socket is connected
|
|
69
|
-
*/
|
|
70
|
-
getIsConnected() {
|
|
71
|
-
return this.isConnected;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Wait for socket to be authenticated
|
|
75
|
-
*/
|
|
76
|
-
async waitForAuth() {
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
const timeout = setTimeout(() => {
|
|
79
|
-
reject(new Error('Authentication timeout'));
|
|
80
|
-
}, 10_000); // 10 second timeout
|
|
81
|
-
this.once('authenticated', (user) => {
|
|
82
|
-
clearTimeout(timeout);
|
|
83
|
-
resolve(user);
|
|
84
|
-
});
|
|
85
|
-
this.once('authError', () => {
|
|
86
|
-
clearTimeout(timeout);
|
|
87
|
-
reject(new Error('Authentication failed'));
|
|
88
|
-
});
|
|
89
|
-
this.once('error', (error) => {
|
|
90
|
-
clearTimeout(timeout);
|
|
91
|
-
reject(error);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Set up socket event handlers
|
|
97
|
-
*/
|
|
98
|
-
setupEventHandlers() {
|
|
99
|
-
if (!this.socket)
|
|
100
|
-
return;
|
|
101
|
-
// Connection events
|
|
102
|
-
this.socket.on('connect', () => {
|
|
103
|
-
logger.info('Socket connected successfully');
|
|
104
|
-
this.isConnected = true;
|
|
105
|
-
this.emit('connected');
|
|
106
|
-
});
|
|
107
|
-
this.socket.on('disconnect', (reason) => {
|
|
108
|
-
logger.warn('Socket disconnected:', reason);
|
|
109
|
-
this.isConnected = false;
|
|
110
|
-
this.emit('disconnected', reason);
|
|
111
|
-
});
|
|
112
|
-
this.socket.on('connect_error', (error) => {
|
|
113
|
-
logger.error('Socket connection error:', error.message);
|
|
114
|
-
this.emit('error', error);
|
|
115
|
-
});
|
|
116
|
-
// Server events
|
|
117
|
-
this.socket.on('auth', (data) => {
|
|
118
|
-
if (data.success) {
|
|
119
|
-
logger.info('Socket authenticated successfully for user:', data.user);
|
|
120
|
-
this.emit('authenticated', data.user);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
logger.error('Socket authentication failed');
|
|
124
|
-
this.emit('authError');
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
this.socket.on('error', (data) => {
|
|
128
|
-
logger.error('Server error:', data.message);
|
|
129
|
-
this.emit('serverError', data.message);
|
|
130
|
-
});
|
|
131
|
-
this.socket.on('update', (data) => {
|
|
132
|
-
logger.debug('Received update:', data);
|
|
133
|
-
this.emit('update', data);
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for the socket client module
|
|
3
|
-
*
|
|
4
|
-
* These tests verify socket connection and authentication with the real server.
|
|
5
|
-
* No mocking is used as per project requirements.
|
|
6
|
-
*/
|
|
7
|
-
import { authGetToken, getOrCreateSecretKey } from '#auth/auth';
|
|
8
|
-
import { getConfig } from '#utils/config';
|
|
9
|
-
import { expect } from 'chai';
|
|
10
|
-
import { SocketClient } from './client.js';
|
|
11
|
-
describe('SocketClient', () => {
|
|
12
|
-
let client = null;
|
|
13
|
-
let authToken;
|
|
14
|
-
before(async () => {
|
|
15
|
-
// Get auth token for tests
|
|
16
|
-
const config = getConfig();
|
|
17
|
-
const secret = await getOrCreateSecretKey();
|
|
18
|
-
authToken = await authGetToken(config.serverUrl, secret);
|
|
19
|
-
});
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
// Clean up socket connection
|
|
22
|
-
if (client) {
|
|
23
|
-
client.disconnect();
|
|
24
|
-
client = null;
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
describe('connection', () => {
|
|
28
|
-
it('should connect to the server with valid auth token', async () => {
|
|
29
|
-
const config = getConfig();
|
|
30
|
-
client = new SocketClient({
|
|
31
|
-
authToken,
|
|
32
|
-
serverUrl: config.serverUrl,
|
|
33
|
-
socketPath: config.socketPath
|
|
34
|
-
});
|
|
35
|
-
client.connect();
|
|
36
|
-
// Wait for authentication
|
|
37
|
-
const user = await client.waitForAuth();
|
|
38
|
-
expect(user).to.be.a('string');
|
|
39
|
-
expect(client.getIsConnected()).to.equal(true);
|
|
40
|
-
});
|
|
41
|
-
it('should emit error with invalid auth token', async () => {
|
|
42
|
-
const config = getConfig();
|
|
43
|
-
client = new SocketClient({
|
|
44
|
-
authToken: 'invalid-token',
|
|
45
|
-
serverUrl: config.serverUrl,
|
|
46
|
-
socketPath: config.socketPath
|
|
47
|
-
});
|
|
48
|
-
client.connect();
|
|
49
|
-
// Should reject with auth error
|
|
50
|
-
try {
|
|
51
|
-
await client.waitForAuth();
|
|
52
|
-
expect.fail('Should have thrown auth error');
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
expect(error.message).to.include('Authentication');
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
describe('events', () => {
|
|
60
|
-
it('should emit connected event on successful connection', (done) => {
|
|
61
|
-
const config = getConfig();
|
|
62
|
-
client = new SocketClient({
|
|
63
|
-
authToken,
|
|
64
|
-
serverUrl: config.serverUrl,
|
|
65
|
-
socketPath: config.socketPath
|
|
66
|
-
});
|
|
67
|
-
client.once('connected', () => {
|
|
68
|
-
expect(client.getIsConnected()).to.equal(true);
|
|
69
|
-
done();
|
|
70
|
-
});
|
|
71
|
-
client.connect();
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
});
|
package/dist/socket/types.d.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Socket message types for handy-cli
|
|
3
|
-
*
|
|
4
|
-
* This module defines TypeScript interfaces for socket communication with the handy server.
|
|
5
|
-
* These types mirror the server's message format for type-safe communication.
|
|
6
|
-
*
|
|
7
|
-
* Key design decisions:
|
|
8
|
-
* - All messages are strongly typed to prevent runtime errors
|
|
9
|
-
* - Message content is encrypted using the session's encryption key
|
|
10
|
-
* - Types match the server's Prisma JSON types exactly
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Base message content structure for encrypted messages
|
|
14
|
-
*/
|
|
15
|
-
export interface SessionMessageContent {
|
|
16
|
-
c: string;
|
|
17
|
-
t: 'encrypted';
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Update body for new messages
|
|
21
|
-
*/
|
|
22
|
-
export interface UpdateBody {
|
|
23
|
-
c: SessionMessageContent | string;
|
|
24
|
-
mid: string;
|
|
25
|
-
sid: string;
|
|
26
|
-
t: 'new-message';
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Update event from server
|
|
30
|
-
*/
|
|
31
|
-
export interface Update {
|
|
32
|
-
content: UpdateBody;
|
|
33
|
-
createdAt: number;
|
|
34
|
-
id: string;
|
|
35
|
-
seq: number;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Socket events from server to client
|
|
39
|
-
*/
|
|
40
|
-
export interface ServerToClientEvents {
|
|
41
|
-
auth: (data: {
|
|
42
|
-
success: boolean;
|
|
43
|
-
user: string;
|
|
44
|
-
}) => void;
|
|
45
|
-
error: (data: {
|
|
46
|
-
message: string;
|
|
47
|
-
}) => void;
|
|
48
|
-
update: (data: Update) => void;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Socket events from client to server
|
|
52
|
-
*/
|
|
53
|
-
export interface ClientToServerEvents {
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Client message types that we'll handle locally
|
|
57
|
-
*/
|
|
58
|
-
export interface TextInputMessage {
|
|
59
|
-
content: string;
|
|
60
|
-
type: 'text-input';
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Session information
|
|
64
|
-
*/
|
|
65
|
-
export interface Session {
|
|
66
|
-
createdAt: number;
|
|
67
|
-
id: string;
|
|
68
|
-
seq: number;
|
|
69
|
-
updatedAt: number;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Session message from API
|
|
73
|
-
*/
|
|
74
|
-
export interface SessionMessage {
|
|
75
|
-
content: SessionMessageContent;
|
|
76
|
-
createdAt: number;
|
|
77
|
-
id: string;
|
|
78
|
-
seq: number;
|
|
79
|
-
updatedAt: number;
|
|
80
|
-
}
|
package/dist/socket/types.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Socket message types for handy-cli
|
|
3
|
-
*
|
|
4
|
-
* This module defines TypeScript interfaces for socket communication with the handy server.
|
|
5
|
-
* These types mirror the server's message format for type-safe communication.
|
|
6
|
-
*
|
|
7
|
-
* Key design decisions:
|
|
8
|
-
* - All messages are strongly typed to prevent runtime errors
|
|
9
|
-
* - Message content is encrypted using the session's encryption key
|
|
10
|
-
* - Types match the server's Prisma JSON types exactly
|
|
11
|
-
*/
|
|
12
|
-
export {};
|
package/dist/utils/config.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration management for handy-cli
|
|
3
|
-
*
|
|
4
|
-
* This module provides hardcoded configuration values for the application.
|
|
5
|
-
*
|
|
6
|
-
* Key responsibilities:
|
|
7
|
-
* - Provide typed configuration object
|
|
8
|
-
* - Centralize configuration constants
|
|
9
|
-
*
|
|
10
|
-
* Design decisions:
|
|
11
|
-
* - Hardcoded values instead of environment variables for simplicity
|
|
12
|
-
* - Server URL points to the known handy-api server
|
|
13
|
-
* - Socket path uses a known path for session updates
|
|
14
|
-
*/
|
|
15
|
-
export interface Config {
|
|
16
|
-
serverUrl: string;
|
|
17
|
-
socketPath: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Get the application configuration
|
|
21
|
-
*/
|
|
22
|
-
export declare function getConfig(): Config;
|
package/dist/utils/config.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration management for handy-cli
|
|
3
|
-
*
|
|
4
|
-
* This module provides hardcoded configuration values for the application.
|
|
5
|
-
*
|
|
6
|
-
* Key responsibilities:
|
|
7
|
-
* - Provide typed configuration object
|
|
8
|
-
* - Centralize configuration constants
|
|
9
|
-
*
|
|
10
|
-
* Design decisions:
|
|
11
|
-
* - Hardcoded values instead of environment variables for simplicity
|
|
12
|
-
* - Server URL points to the known handy-api server
|
|
13
|
-
* - Socket path uses a known path for session updates
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Get the application configuration
|
|
17
|
-
*/
|
|
18
|
-
export function getConfig() {
|
|
19
|
-
return {
|
|
20
|
-
serverUrl: 'https://handy-api.korshakov.org',
|
|
21
|
-
socketPath: '/v1/updates'
|
|
22
|
-
};
|
|
23
|
-
}
|
package/dist/utils/logger.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logger utility for handy-cli
|
|
3
|
-
*
|
|
4
|
-
* This module provides structured logging with different log levels and colors.
|
|
5
|
-
*
|
|
6
|
-
* Key responsibilities:
|
|
7
|
-
* - Provide consistent logging interface
|
|
8
|
-
* - Color-coded output for different log levels
|
|
9
|
-
* - Timestamp prefixes for better debugging
|
|
10
|
-
*/
|
|
11
|
-
export declare enum LogLevel {
|
|
12
|
-
DEBUG = "DEBUG",
|
|
13
|
-
ERROR = "ERROR",
|
|
14
|
-
INFO = "INFO",
|
|
15
|
-
WARN = "WARN"
|
|
16
|
-
}
|
|
17
|
-
declare class Logger {
|
|
18
|
-
debug(message: string, ...args: unknown[]): void;
|
|
19
|
-
error(message: string, ...args: unknown[]): void;
|
|
20
|
-
info(message: string, ...args: unknown[]): void;
|
|
21
|
-
warn(message: string, ...args: unknown[]): void;
|
|
22
|
-
private getTimestamp;
|
|
23
|
-
private log;
|
|
24
|
-
}
|
|
25
|
-
export declare const logger: Logger;
|
|
26
|
-
export {};
|