Initial checkin
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
// server.js — minimal Web Push backend.
|
||||
//
|
||||
// Setup:
|
||||
// npm init -y
|
||||
// npm install express web-push
|
||||
// npx web-push generate-vapid-keys # paste the two keys below
|
||||
// node server.js
|
||||
//
|
||||
// Serves the static test page from ./public, stores subscriptions in memory,
|
||||
// and exposes /api/send to push to every stored subscription.
|
||||
|
||||
const express = require('express');
|
||||
const webpush = require('web-push');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
// --- VAPID keys -----------------------------------------------------------
|
||||
// Paste the output of `npx web-push generate-vapid-keys` here.
|
||||
|
||||
const VAPID_PUBLIC = 'BDjn64xCA8SGTAZy8Tes-Kqm44sgFTyZlgXRfpeKvUjSSFdnfI4ru0jY64JExOlfV4qNke7kqKb6B_sBUmbTdIY';
|
||||
const VAPID_PRIVATE = 'u2cXEA3HC2FUY7f4FedQNqnAcOeFdfG655WK_ktYWbQ';
|
||||
|
||||
webpush.setVapidDetails(
|
||||
'mailto:simon@unisolve.com.au', // contact the push service can reach if there's a problem
|
||||
VAPID_PUBLIC,
|
||||
VAPID_PRIVATE
|
||||
);
|
||||
|
||||
// Expose the public key so the page can subscribe without hardcoding it.
|
||||
app.get('/api/vapidPublicKey', (req, res) => res.send(VAPID_PUBLIC));
|
||||
|
||||
// --- Subscription store ---------------------------------------------------
|
||||
// In-memory for testing. Use a real table (one row per device) in production.
|
||||
const subscriptions = new Map(); // endpoint -> subscription object
|
||||
|
||||
app.post('/api/subscribe', (req, res) => {
|
||||
const sub = req.body;
|
||||
if (!sub || !sub.endpoint) return res.status(400).json({ error: 'bad subscription' });
|
||||
subscriptions.set(sub.endpoint, sub);
|
||||
console.log('Stored subscription. Total:', subscriptions.size);
|
||||
res.status(201).json({ ok: true });
|
||||
});
|
||||
|
||||
// --- Send a push to everyone ----------------------------------------------
|
||||
// POST /api/send { "title": "...", "body": "..." }
|
||||
app.post('/api/send', async (req, res) => {
|
||||
const payload = JSON.stringify({
|
||||
title: req.body.title || 'Test push',
|
||||
body: req.body.body || 'Sent from the server at ' + new Date().toLocaleTimeString()
|
||||
});
|
||||
|
||||
const results = [];
|
||||
for (const [endpoint, sub] of subscriptions) {
|
||||
try {
|
||||
await webpush.sendNotification(sub, payload);
|
||||
results.push({ endpoint, ok: true });
|
||||
} catch (err) {
|
||||
// 404/410 mean the subscription is dead — drop it so we stop trying.
|
||||
if (err.statusCode === 404 || err.statusCode === 410) {
|
||||
subscriptions.delete(endpoint);
|
||||
results.push({ endpoint, ok: false, removed: true });
|
||||
} else {
|
||||
results.push({ endpoint, ok: false, status: err.statusCode });
|
||||
}
|
||||
}
|
||||
}
|
||||
res.json({ sent: results.length, results });
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 8000;
|
||||
app.listen(PORT, () => console.log(`Listening on http://localhost:${PORT}`));
|
||||
Reference in New Issue
Block a user