Skip to content

Instantly share code, notes, and snippets.

@pHo9UBenaA
Last active March 18, 2026 14:06
Show Gist options
  • Select an option

  • Save pHo9UBenaA/7fcb4359ab5fbadb8e83e8f3ccc42069 to your computer and use it in GitHub Desktop.

Select an option

Save pHo9UBenaA/7fcb4359ab5fbadb8e83e8f3ccc42069 to your computer and use it in GitHub Desktop.
A lightweight local HTTP server that triggers macOS notifications via AppleScript.
// Notifications triggered via osascript are handled by Script Editor, so make sure notifications are enabled for Script Editor in macOS System Settings.
// Run: nohup node notify-server.mjs
// Test: curl "http://host.docker.internal:8100/notify?title=Title&message=$(node -p 'encodeURIComponent(`Write your message here`)')"
import http from 'node:http';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileAsync = promisify(execFile);
const HOST = '127.0.0.1';
const PORT = Number(process.env.PORT ?? 8100);
function escapeAppleScriptString(value) {
return String(value)
.replaceAll('\\', '\\\\')
.replaceAll('"', '\\"');
}
function createNotificationScript({ title, message, sound }) {
const escapedTitle = escapeAppleScriptString(title);
const escapedMessage = escapeAppleScriptString(message);
const escapedSound = escapeAppleScriptString(sound);
return `display notification "${escapedMessage}" with title "${escapedTitle}" sound name "${escapedSound}"`;
}
async function handleNotify(req, res) {
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? `${HOST}:${PORT}`}`);
const title = url.searchParams.get('title') ?? 'You have a notification';
const message = url.searchParams.get('message') ?? '';
const sound = url.searchParams.get('sound') ?? 'Funk';
const script = createNotificationScript({ title, message, sound });
try {
await execFileAsync('osascript', ['-e', script]);
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('OK\n');
} catch (error) {
console.error('Failed to send notification:', error);
if (error?.stderr) {
console.error(error.stderr);
}
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('NG\n');
}
}
const server = http.createServer(async (req, res) => {
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? `${HOST}:${PORT}`}`);
if (url.pathname === '/notify') {
await handleNotify(req, res);
return;
}
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Not Found\n');
});
server.listen(PORT, HOST, () => {
console.log(`Notification server is listening at http://${HOST}:${PORT} ...`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment