Skip to main content

Core API

@jetstart/core exports the JetStartServer class and the individual pipeline components. The CLI uses all of these internally; you can use them directly if you want to embed JetStart in a custom tool.


JetStartServer

The main class. Creates and coordinates the HTTP server, WebSocket server, file watcher, and hot reload pipeline.

Constructor

import { JetStartServer } from '@jetstart/core';

const server = new JetStartServer({
httpPort: 8765, // HTTP server port (default: DEFAULT_CORE_PORT)
wsPort: 8766, // WebSocket server port (default: DEFAULT_WS_PORT)
host: '0.0.0.0', // Bind address — use 0.0.0.0 to accept all interfaces
displayHost: '192.168.1.100', // LAN IP shown in QR code and terminal
projectPath: '/path/to/my-app',
projectName: 'my-app',
emulatorHost: '10.0.2.2', // Optional: override host injected into BuildConfig for AVD
});

server.start()

Starts all three servers, creates a session, and begins watching for file changes.

const session = await server.start();

console.log(session.id); // e.g. "a1b2c3"
console.log(session.token); // e.g. "xyz789abc"

Returns a ServerSession object with id, token, projectName, projectPath, createdAt, lastActivity.

server.stop()

Gracefully shuts down all servers and stops the file watcher.

await server.stop();

server.on(event, handler)

Listen for server events:

server.on('build:complete', (result) => {
console.log('APK ready at:', result.apkPath);
console.log('Build time:', result.buildTime, 'ms');
});

server.on('build:start', () => {
console.log('Build started');
});

server.on('build:error', (error) => {
console.error('Build failed:', error.message);
});

server.on('client:connected', (sessionId) => {
console.log('Client connected to session:', sessionId);
});

HotReloadService

Orchestrates the Kotlin → .class → $Override → DEX pipeline for a single file.

import { HotReloadService } from '@jetstart/core';

const service = new HotReloadService('/path/to/project');

// Check environment before starting
const { ready, issues } = await service.checkEnvironment();
if (!ready) {
issues.forEach(i => console.error(i));
// Issues include: "kotlinc not found", "d8 not found", "Cannot build classpath"
}

// Compile a changed file and get the DEX payload
const result = await service.hotReload('/path/to/project/app/src/main/java/com/example/MainActivity.kt');

if (result.success) {
console.log(`Compiled in ${result.compileTime}ms, DEX in ${result.dexTime}ms`);
console.log('Classes patched:', result.classNames);
// result.dexBase64 — send this via WebSocket as core:dex-reload
} else {
console.error('Hot reload failed:', result.errors);
}

HotReloadResult

interface HotReloadResult {
success: boolean;
dexBase64: string | null; // Base64-encoded classes.dex
classNames: string[]; // Fully-qualified names of all patched classes
errors: string[];
compileTime: number; // ms for kotlinc step
dexTime: number; // ms for d8 step
}

KotlinCompiler

Compiles a single Kotlin source file to .class files.

import { KotlinCompiler } from '@jetstart/core';

const compiler = new KotlinCompiler('/path/to/project');

// Find kotlinc executable
const kotlincPath = await compiler.findKotlinc(); // null if not found

// Build classpath from SDK + Gradle caches
const classpath = await compiler.buildClasspath();

// Compile a file
const result = await compiler.compileFile('/path/to/MainActivity.kt');
// result.success, result.classFiles, result.errors, result.outputDir

DexGenerator

Converts .class files to a classes.dex using Android's d8 tool.

import { DexGenerator } from '@jetstart/core';

const generator = new DexGenerator();

const d8Path = await generator.findD8(); // null if not found

const result = await generator.generateDex(classFiles, outputDir);
// result.success, result.dexPath, result.dexBytes (Buffer), result.errors

FileWatcher

Watches for file changes and invokes a callback with the changed paths.

import { FileWatcher } from '@jetstart/core';

const watcher = new FileWatcher({
projectPath: '/path/to/project',
callback: (changedFiles: string[]) => {
console.log('Changed:', changedFiles);
},
debounceMs: 300, // optional, default 300
});

watcher.watch('/path/to/project');
// Watches: **/*.kt, **/*.xml, **/*.gradle, **/*.gradle.kts
// Ignores: node_modules, build, .gradle, .git, dist

watcher.stop();

SessionManager

Creates and manages development sessions.

import { SessionManager } from '@jetstart/core';

const manager = new SessionManager();

const session = await manager.createSession({
projectName: 'my-app',
projectPath: '/path/to/project',
});
// session.id, session.token, session.createdAt, session.lastActivity

const retrieved = manager.getSession(session.id);

manager.updateActivity(session.id);

manager.deleteSession(session.id);

manager.cleanupExpiredSessions();
// Removes sessions idle for more than SESSION_IDLE_TIMEOUT (30 minutes)

generateQRCode

Generates a QR code PNG as a base64 data URL.

import { generateQRCode } from '@jetstart/core';

const qrCode = await generateQRCode({
sessionId: 'a1b2c3',
serverUrl: 'http://192.168.1.100:8765',
wsUrl: 'ws://192.168.1.100:8766',
token: 'xyz789abc',
projectName: 'my-app',
version: '0.1.0',
});
// Returns: "data:image/png;base64,..."

The QR content uses the compact format: host|port|wsPort|sessionId|token|projectName.


Logger utilities

import { log, success, error, warning, info } from '@jetstart/core';

log('Informational message');
success('Operation completed');
error('Something failed');
warning('Non-fatal warning');
info('Server running on port 8765');

Exported Types

All types from @jetstart/shared are re-exported from @jetstart/core:

export type {
Session,
SessionStatus,
BuildConfig,
BuildResult,
DeviceInfo,
WSMessage,
} from '@jetstart/shared';

Core-specific types:

interface ServerSession {
id: string;
token: string;
projectName: string;
projectPath: string;
createdAt: number;
lastActivity: number;
}

interface QRCodeOptions {
sessionId: string;
serverUrl: string;
wsUrl: string;
token: string;
projectName: string;
version: string;
}