@jetstart/core 1.1.1
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/.eslintrc.json +6 -0
- package/README.md +124 -0
- package/dist/build/builder.d.ts +57 -0
- package/dist/build/builder.d.ts.map +1 -0
- package/dist/build/builder.js +151 -0
- package/dist/build/builder.js.map +1 -0
- package/dist/build/cache.d.ts +51 -0
- package/dist/build/cache.d.ts.map +1 -0
- package/dist/build/cache.js +152 -0
- package/dist/build/cache.js.map +1 -0
- package/dist/build/dsl-parser.d.ts +54 -0
- package/dist/build/dsl-parser.d.ts.map +1 -0
- package/dist/build/dsl-parser.js +373 -0
- package/dist/build/dsl-parser.js.map +1 -0
- package/dist/build/dsl-types.d.ts +47 -0
- package/dist/build/dsl-types.d.ts.map +1 -0
- package/dist/build/dsl-types.js +7 -0
- package/dist/build/dsl-types.js.map +1 -0
- package/dist/build/gradle-injector.d.ts +14 -0
- package/dist/build/gradle-injector.d.ts.map +1 -0
- package/dist/build/gradle-injector.js +77 -0
- package/dist/build/gradle-injector.js.map +1 -0
- package/dist/build/gradle.d.ts +43 -0
- package/dist/build/gradle.d.ts.map +1 -0
- package/dist/build/gradle.js +281 -0
- package/dist/build/gradle.js.map +1 -0
- package/dist/build/index.d.ts +10 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +26 -0
- package/dist/build/index.js.map +1 -0
- package/dist/build/parser.d.ts +12 -0
- package/dist/build/parser.d.ts.map +1 -0
- package/dist/build/parser.js +71 -0
- package/dist/build/parser.js.map +1 -0
- package/dist/build/watcher.d.ts +30 -0
- package/dist/build/watcher.d.ts.map +1 -0
- package/dist/build/watcher.js +120 -0
- package/dist/build/watcher.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/server/http.d.ts +12 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +32 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/index.d.ts +35 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +262 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware.d.ts +7 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/middleware.js +42 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/routes.d.ts +7 -0
- package/dist/server/routes.d.ts.map +1 -0
- package/dist/server/routes.js +104 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +23 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +33 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/qr.d.ts +8 -0
- package/dist/utils/qr.d.ts.map +1 -0
- package/dist/utils/qr.js +48 -0
- package/dist/utils/qr.js.map +1 -0
- package/dist/utils/session.d.ts +18 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/dist/utils/session.js +49 -0
- package/dist/utils/session.js.map +1 -0
- package/dist/websocket/handler.d.ts +25 -0
- package/dist/websocket/handler.d.ts.map +1 -0
- package/dist/websocket/handler.js +126 -0
- package/dist/websocket/handler.js.map +1 -0
- package/dist/websocket/index.d.ts +18 -0
- package/dist/websocket/index.d.ts.map +1 -0
- package/dist/websocket/index.js +40 -0
- package/dist/websocket/index.js.map +1 -0
- package/dist/websocket/manager.d.ts +16 -0
- package/dist/websocket/manager.d.ts.map +1 -0
- package/dist/websocket/manager.js +58 -0
- package/dist/websocket/manager.js.map +1 -0
- package/package.json +78 -0
- package/src/build/builder.ts +192 -0
- package/src/build/cache.ts +144 -0
- package/src/build/dsl-parser.ts +382 -0
- package/src/build/dsl-types.ts +50 -0
- package/src/build/gradle-injector.ts +64 -0
- package/src/build/gradle.ts +305 -0
- package/src/build/index.ts +10 -0
- package/src/build/parser.ts +75 -0
- package/src/build/watcher.ts +103 -0
- package/src/index.ts +20 -0
- package/src/server/http.ts +38 -0
- package/src/server/index.ts +272 -0
- package/src/server/middleware.ts +43 -0
- package/src/server/routes.ts +116 -0
- package/src/types/index.ts +21 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/logger.ts +28 -0
- package/src/utils/qr.ts +46 -0
- package/src/utils/session.ts +58 -0
- package/src/websocket/handler.ts +150 -0
- package/src/websocket/index.ts +56 -0
- package/src/websocket/manager.ts +63 -0
- package/tests/build.test.ts +13 -0
- package/tests/server.test.ts +13 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Message Handler
|
|
3
|
+
* Processes incoming WebSocket messages
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
WSMessage,
|
|
8
|
+
ClientMessage,
|
|
9
|
+
CoreConnectedMessage,
|
|
10
|
+
CoreBuildStartMessage,
|
|
11
|
+
CoreBuildCompleteMessage,
|
|
12
|
+
CoreUIUpdateMessage,
|
|
13
|
+
} from '@jetstart/shared';
|
|
14
|
+
import { ConnectionManager } from './manager';
|
|
15
|
+
import { log, error as logError } from '../utils/logger';
|
|
16
|
+
|
|
17
|
+
export class WebSocketHandler {
|
|
18
|
+
private onClientConnected?: (sessionId: string) => void;
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
private connectionManager: ConnectionManager,
|
|
22
|
+
options?: { onClientConnected?: (sessionId: string) => void }
|
|
23
|
+
) {
|
|
24
|
+
this.onClientConnected = options?.onClientConnected;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
handleMessage(clientId: string, data: Buffer): void {
|
|
28
|
+
try {
|
|
29
|
+
const message: WSMessage = JSON.parse(data.toString());
|
|
30
|
+
log(`Received message from ${clientId}: ${message.type}`);
|
|
31
|
+
|
|
32
|
+
// Route message based on type
|
|
33
|
+
if (this.isClientMessage(message)) {
|
|
34
|
+
this.handleClientMessage(clientId, message);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
} catch (err: any) {
|
|
38
|
+
logError(`Failed to parse message from ${clientId}: ${err.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private isClientMessage(message: WSMessage): message is ClientMessage {
|
|
43
|
+
return message.type.startsWith('client:');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private handleClientMessage(clientId: string, message: ClientMessage): void {
|
|
47
|
+
switch (message.type) {
|
|
48
|
+
case 'client:connect':
|
|
49
|
+
this.handleConnect(clientId, message);
|
|
50
|
+
break;
|
|
51
|
+
case 'client:status':
|
|
52
|
+
log(`Client ${clientId} status: ${message.status}`);
|
|
53
|
+
break;
|
|
54
|
+
case 'client:log':
|
|
55
|
+
// Forward to logs service
|
|
56
|
+
break;
|
|
57
|
+
case 'client:heartbeat':
|
|
58
|
+
// Update last activity
|
|
59
|
+
break;
|
|
60
|
+
case 'client:disconnect':
|
|
61
|
+
this.handleDisconnect(clientId, message);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private handleConnect(clientId: string, message: ClientMessage & { type: 'client:connect' }): void {
|
|
67
|
+
log(`Client connecting with session: ${message.sessionId}`);
|
|
68
|
+
|
|
69
|
+
// Send connected confirmation
|
|
70
|
+
const response: CoreConnectedMessage = {
|
|
71
|
+
type: 'core:connected',
|
|
72
|
+
timestamp: Date.now(),
|
|
73
|
+
sessionId: message.sessionId,
|
|
74
|
+
projectName: 'DemoProject', // In real implementation, get from session
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
this.connectionManager.sendToClient(clientId, response);
|
|
78
|
+
|
|
79
|
+
// Trigger initial build for the client
|
|
80
|
+
if (this.onClientConnected) {
|
|
81
|
+
log(`Triggering initial build for session: ${message.sessionId}`);
|
|
82
|
+
this.onClientConnected(message.sessionId);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private handleDisconnect(clientId: string, message: ClientMessage & { type: 'client:disconnect' }): void {
|
|
87
|
+
log(`Client disconnecting: ${message.reason || 'No reason provided'}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Send build notifications
|
|
91
|
+
sendBuildStart(sessionId: string): void {
|
|
92
|
+
const message: CoreBuildStartMessage = {
|
|
93
|
+
type: 'core:build-start',
|
|
94
|
+
timestamp: Date.now(),
|
|
95
|
+
sessionId,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
this.connectionManager.broadcast(message);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
sendBuildComplete(sessionId: string, apkUrl: string): void {
|
|
102
|
+
const message: CoreBuildCompleteMessage = {
|
|
103
|
+
type: 'core:build-complete',
|
|
104
|
+
timestamp: Date.now(),
|
|
105
|
+
sessionId,
|
|
106
|
+
apkInfo: {
|
|
107
|
+
path: '/path/to/app.apk',
|
|
108
|
+
size: 5242880,
|
|
109
|
+
hash: 'abc123',
|
|
110
|
+
versionCode: 1,
|
|
111
|
+
versionName: '1.0.0',
|
|
112
|
+
minSdkVersion: 24,
|
|
113
|
+
targetSdkVersion: 34,
|
|
114
|
+
applicationId: 'com.example.app',
|
|
115
|
+
},
|
|
116
|
+
downloadUrl: apkUrl,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
this.connectionManager.broadcast(message);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Send UI update (DSL-based hot reload)
|
|
124
|
+
*/
|
|
125
|
+
sendUIUpdate(sessionId: string, dslContent: string, screens?: string[]): void {
|
|
126
|
+
const message: CoreUIUpdateMessage = {
|
|
127
|
+
type: 'core:ui-update',
|
|
128
|
+
timestamp: Date.now(),
|
|
129
|
+
sessionId,
|
|
130
|
+
dslContent,
|
|
131
|
+
screens,
|
|
132
|
+
hash: this.generateHash(dslContent),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
log(`Sending UI update: ${dslContent.length} bytes`);
|
|
136
|
+
log(`DSL Content: ${dslContent}`);
|
|
137
|
+
this.connectionManager.broadcast(message);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private generateHash(content: string): string {
|
|
141
|
+
// Simple hash for caching (in production, use crypto.createHash)
|
|
142
|
+
let hash = 0;
|
|
143
|
+
for (let i = 0; i < content.length; i++) {
|
|
144
|
+
const char = content.charCodeAt(i);
|
|
145
|
+
hash = ((hash << 5) - hash) + char;
|
|
146
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
147
|
+
}
|
|
148
|
+
return hash.toString(16);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Server
|
|
3
|
+
* Real-time communication with clients
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
7
|
+
import { Server } from 'http';
|
|
8
|
+
import { WebSocketHandler } from './handler';
|
|
9
|
+
import { ConnectionManager } from './manager';
|
|
10
|
+
import { log } from '../utils/logger';
|
|
11
|
+
|
|
12
|
+
export interface WebSocketConfig {
|
|
13
|
+
port: number;
|
|
14
|
+
server?: Server;
|
|
15
|
+
onClientConnected?: (sessionId: string) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface WebSocketServerResult {
|
|
19
|
+
server: WebSocketServer;
|
|
20
|
+
handler: WebSocketHandler;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function createWebSocketServer(config: WebSocketConfig): Promise<WebSocketServerResult> {
|
|
24
|
+
const wss = new WebSocketServer({
|
|
25
|
+
port: config.port,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const connectionManager = new ConnectionManager();
|
|
29
|
+
const handler = new WebSocketHandler(connectionManager, {
|
|
30
|
+
onClientConnected: config.onClientConnected,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
wss.on('connection', (ws: WebSocket, _request) => {
|
|
34
|
+
const clientId = connectionManager.addConnection(ws);
|
|
35
|
+
log(`WebSocket client connected: ${clientId}`);
|
|
36
|
+
|
|
37
|
+
// Handle messages
|
|
38
|
+
ws.on('message', (data: Buffer) => {
|
|
39
|
+
handler.handleMessage(clientId, data);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Handle disconnection
|
|
43
|
+
ws.on('close', () => {
|
|
44
|
+
log(`WebSocket client disconnected: ${clientId}`);
|
|
45
|
+
connectionManager.removeConnection(clientId);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Handle errors
|
|
49
|
+
ws.on('error', (err: Error) => {
|
|
50
|
+
console.error(`WebSocket error for ${clientId}:`, err.message);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
log(`WebSocket server listening on port ${config.port}`);
|
|
55
|
+
return { server: wss, handler };
|
|
56
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection Manager
|
|
3
|
+
* Manages WebSocket connections
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { WebSocket } from 'ws';
|
|
7
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
8
|
+
import { CoreMessage } from '@jetstart/shared';
|
|
9
|
+
|
|
10
|
+
export class ConnectionManager {
|
|
11
|
+
private connections: Map<string, WebSocket> = new Map();
|
|
12
|
+
|
|
13
|
+
addConnection(ws: WebSocket): string {
|
|
14
|
+
const id = uuidv4();
|
|
15
|
+
this.connections.set(id, ws);
|
|
16
|
+
return id;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
removeConnection(id: string): void {
|
|
20
|
+
this.connections.delete(id);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getConnection(id: string): WebSocket | undefined {
|
|
24
|
+
return this.connections.get(id);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
sendToClient(clientId: string, message: CoreMessage): boolean {
|
|
28
|
+
const ws = this.connections.get(clientId);
|
|
29
|
+
|
|
30
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
ws.send(JSON.stringify(message));
|
|
36
|
+
return true;
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error(`Failed to send message to ${clientId}:`, err);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
broadcast(message: CoreMessage): void {
|
|
44
|
+
const data = JSON.stringify(message);
|
|
45
|
+
const connectionCount = Array.from(this.connections.values()).filter(ws => ws.readyState === WebSocket.OPEN).length;
|
|
46
|
+
console.log(`[ConnectionManager] Broadcasting ${message.type} to ${connectionCount} connected clients`);
|
|
47
|
+
|
|
48
|
+
this.connections.forEach((ws, clientId) => {
|
|
49
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
50
|
+
try {
|
|
51
|
+
ws.send(data);
|
|
52
|
+
console.log(`[ConnectionManager] Sent ${message.type} to client ${clientId}`);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error(`Failed to broadcast to ${clientId}:`, err);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getConnectionCount(): number {
|
|
61
|
+
return this.connections.size;
|
|
62
|
+
}
|
|
63
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"composite": true,
|
|
17
|
+
"outDir": "./dist",
|
|
18
|
+
"rootDir": "./src"
|
|
19
|
+
},
|
|
20
|
+
"references": [
|
|
21
|
+
{ "path": "../shared" }
|
|
22
|
+
],
|
|
23
|
+
"include": ["src/**/*"],
|
|
24
|
+
"exclude": ["node_modules", "dist", "tests"]
|
|
25
|
+
}
|