UNPKG

imessage-ts

Version:

TypeScript library for interacting with iMessage on macOS - send messages, monitor chats, and automate responses

203 lines 8.21 kB
#!/usr/bin/env node "use strict"; 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