imessage-ts
Version:
TypeScript library for interacting with iMessage on macOS - send messages, monitor chats, and automate responses
203 lines • 8.21 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const index_1 = require("../index");
const server_1 = require("../server");
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const os_1 = __importDefault(require("os"));
const program = new commander_1.Command();
// Check if we have access to the iMessage database
async function checkPermissions() {
const dbPath = path_1.default.join(os_1.default.homedir(), 'Library/Messages/chat.db');
try {
// Try to access the database file
await fs_extra_1.default.access(dbPath, fs_extra_1.default.constants.R_OK);
return true;
}
catch (error) {
return false;
}
}
// Display permission error and instructions
function showPermissionError() {
console.error('\n❌ Permission Error: Cannot access iMessage database\n');
console.error('To fix this issue, you need to grant Full Disk Access to your Terminal:\n');
console.error('1. Open System Preferences > Security & Privacy > Privacy tab');
console.error('2. Select "Full Disk Access" from the left sidebar');
console.error('3. Click the lock icon to make changes');
console.error('4. Click the "+" button and add your Terminal app:');
console.error(' - For Terminal.app: /Applications/Utilities/Terminal.app');
console.error(' - For iTerm2: /Applications/iTerm.app');
console.error(' - For VS Code: /Applications/Visual Studio Code.app');
console.error('5. Restart your Terminal application\n');
if (process.getuid && process.getuid() !== 0) {
console.error('Note: Running with sudo will NOT fix this issue.');
console.error('Full Disk Access must be granted through System Preferences.\n');
}
process.exit(1);
}
// Wrapper to check permissions before running commands
function withPermissionCheck(fn) {
return async (...args) => {
const hasPermission = await checkPermissions();
if (!hasPermission) {
showPermissionError();
}
return fn(...args);
};
}
program
.name('imessage-ts')
.description('iMessage TypeScript SDK CLI')
.version('0.1.0');
program
.command('run-server')
.description('Run the iMessage HTTP server')
.option('-p, --port <number>', 'Server port', '3000')
.option('-w, --webhook <url>', 'Webhook URL to send events to')
.option('--whitelist <handles...>', 'Whitelisted senders (space-separated)')
.option('--auto-respond', 'Enable auto-responder for whitelisted senders')
.option('--api-key <key>', 'API key for authentication (optional)')
.option('--config <path>', 'Path to config file')
.option('--temp-attachments-dir <path>', 'Directory to save temporary attachments (default: system temp)')
.action(withPermissionCheck(async (options) => {
console.log('Starting iMessage HTTP Server...');
// Load config from file if provided
let config = {};
if (options.config) {
try {
config = await fs_extra_1.default.readJson(options.config);
console.log(`Loaded config from ${options.config}`);
}
catch (error) {
console.error(`Failed to load config: ${error}`);
}
}
// Merge CLI options with config file
const serverConfig = {
port: parseInt(options.port),
webhookUrl: options.webhook,
whitelistedSenders: options.whitelist || config?.whitelistedSenders || [],
autoRespond: options.autoRespond || config?.autoRespond || false,
apiKey: options.apiKey || config?.apiKey,
tempAttachmentsDir: options.tempAttachmentsDir || config?.tempAttachmentsDir,
};
// Create and start server
const server = new server_1.IMessageServer(serverConfig);
await server.start();
}));
program
.command('send')
.description('Send a message')
.requiredOption('-t, --to <recipient>', 'Recipient phone number or email')
.requiredOption('-m, --message <text>', 'Message text')
.option('-s, --service <type>', 'Service type (iMessage or SMS)', 'iMessage')
.option('-a, --attachment <path>', 'Path to attachment')
.action(withPermissionCheck(async (options) => {
console.log('Sending message...');
const client = new index_1.IMessageClient();
await client.initialize();
try {
await client.sendMessage({
to: options.to,
text: options.message,
service: options.service.toLowerCase() === 'sms' ? index_1.MessageService.SMS : index_1.MessageService.IMESSAGE,
attachments: options.attachment ? [options.attachment] : undefined
});
console.log('✅ Message sent successfully!');
}
catch (error) {
console.error('❌ Failed to send message:', error);
}
finally {
client.close();
}
}));
program
.command('list-conversations')
.description('List recent conversations')
.option('-l, --limit <number>', 'Number of conversations to show', '10')
.action(withPermissionCheck(async (options) => {
console.log('Fetching conversations...');
const client = new index_1.IMessageClient();
await client.initialize();
try {
const conversations = await client.getConversations({
limit: parseInt(options.limit)
});
console.log(`\nFound ${conversations.length} conversations:\n`);
conversations.forEach((conv, index) => {
console.log(`${index + 1}. ${conv.displayName || conv.chatIdentifier}`);
console.log(` ID: ${conv.id}`);
console.log(` Type: ${conv.isGroup ? 'Group' : 'Individual'}`);
console.log(` Participants: ${conv.participants.length}`);
console.log('');
});
}
catch (error) {
console.error('❌ Failed to fetch conversations:', error);
}
finally {
client.close();
}
}));
program
.command('watch')
.description('Watch for new messages')
.option('--json', 'Output messages as JSON')
.action(withPermissionCheck(async (options) => {
console.log('Watching for new messages... (Ctrl+C to stop)');
const client = new index_1.IMessageClient();
await client.initialize();
client.on('message', (event) => {
if (options.json) {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
sender: event.message.handle,
text: event.message.text,
isFromMe: event.message.isFromMe,
service: event.message.service,
conversationId: event.conversation.id
}));
}
else {
console.log(`\n[${new Date().toLocaleTimeString()}] New message:`);
console.log(`From: ${event.message.isFromMe ? 'Me' : event.message.handle}`);
console.log(`Text: ${event.message.text || '[No text]'}`);
console.log(`Service: ${event.message.service}`);
}
});
client.startWatching();
// Keep process running
process.stdin.resume();
process.on('SIGINT', () => {
console.log('\nStopping message watcher...');
client.stopWatching();
client.close();
process.exit();
});
}));
// Add a check permissions command
program
.command('check-permissions')
.description('Check if the CLI has proper permissions to access iMessage')
.action(async () => {
console.log('Checking permissions...\n');
const hasPermission = await checkPermissions();
const dbPath = path_1.default.join(os_1.default.homedir(), 'Library/Messages/chat.db');
console.log(`Database path: ${dbPath}`);
console.log(`Accessible: ${hasPermission ? '✅ Yes' : '❌ No'}`);
if (hasPermission) {
console.log('\n✅ Great! You have the necessary permissions to use imessage-ts.');
}
else {
showPermissionError();
}
});
program.parse();
//# sourceMappingURL=index.js.map