demos for spacedust

minimal api server landing

+17 -162
+17 -133
server/web-content/index.html
··· 1 1 <!doctype html> 2 - <style> 3 - #error-message { 4 - color: tomato; 5 - } 6 - </style> 7 - 8 - hiiiiii 9 - 10 - <label><input id="did" placeholder="did:plc:..." /> DID</label> 11 - <button id="subscribe">subscribe</button> 12 - 13 - <p id="error-message"></p> 14 - 15 - 16 - <script> 17 - const err = m => { 18 - document.getElementById('error-message').textContent = m; 19 - throw new Error(m); 20 - }; 21 - const clearErr = () => { 22 - document.getElementById('error-message').textContent = ''; 23 - }; 24 - 25 - if (!('serviceWorker' in navigator)) err('service worker not supported'); 26 - 27 - if (!('PushManager' in window)) err('push not supported'); 28 - 29 - function urlBase64ToUint8Array(base64String) { 30 - var padding = '='.repeat((4 - base64String.length % 4) % 4); 31 - var base64 = (base64String + padding) 32 - .replace(/\-/g, '+') 33 - .replace(/_/g, '/'); 34 - 35 - var rawData = window.atob(base64); 36 - var outputArray = new Uint8Array(rawData.length); 37 - 38 - for (var i = 0; i < rawData.length; ++i) { 39 - outputArray[i] = rawData.charCodeAt(i); 40 - } 41 - return outputArray; 42 - } 43 - 44 - function registerServiceWorker() { 45 - return navigator.serviceWorker 46 - .register('/service-worker.js') 47 - .then(function (registration) { 48 - console.log('Service worker successfully registered.'); 49 - return registration; 50 - }) 51 - .catch(function (err) { 52 - console.error('Unable to register service worker.', err); 53 - }); 54 - } 55 - 56 - function askPermission() { 57 - return new Promise(function (resolve, reject) { 58 - const permissionResult = Notification.requestPermission(function (result) { 59 - resolve(result); 60 - }); 61 - 62 - if (permissionResult) { 63 - permissionResult.then(resolve, reject); 64 - } 65 - }).then(function (permissionResult) { 66 - if (permissionResult !== 'granted') { 67 - throw new Error("We weren't granted permission."); 68 - } 69 - }); 70 - } 71 - 72 - function subscribeUserToPush() { 73 - return navigator.serviceWorker 74 - .register('/service-worker.js') 75 - .then(function (registration) { 76 - const subscribeOptions = { 77 - userVisibleOnly: true, 78 - applicationServerKey: urlBase64ToUint8Array(PUBKEY), 79 - }; 80 - 81 - return registration.pushManager.subscribe(subscribeOptions); 82 - }) 83 - .then(function (pushSubscription) { 84 - console.log( 85 - 'Received PushSubscription: ', 86 - JSON.stringify(pushSubscription), 87 - ); 88 - return pushSubscription; 89 - }); 90 - } 91 - 92 - document.getElementById('subscribe').addEventListener('click', async () => { 93 - clearErr(); 94 - 95 - const did = document.getElementById('did').value; 96 - if (!did.startsWith('did:')) err('should start with `did:`'); 97 - 98 - let perm; 99 - try { 100 - perm = await askPermission(); 101 - } catch (err) { 102 - console.error(err); 103 - err('notification permissions are needed to give you notifications'); 104 - } 105 - 106 - let sub; 107 - try { 108 - sub = await subscribeUserToPush(); 109 - } catch (err) { 110 - console.error(err); 111 - err('failed to subscribe for notification'); 112 - } 113 - 114 - let res; 115 - try { 116 - res = await fetch('/subscribe', { 117 - method: 'POST', 118 - body: JSON.stringify({ did, sub }), 119 - headers: { 120 - 'Content-Type': 'application/json', 121 - }, 122 - }); 123 - } catch (err) { 124 - console.error(err); 125 - err('failed to create subscription with backend'); 126 - } 127 - 128 - if (!res.ok) { 129 - console.error(await res.text()); 130 - err('not-ok response trying to create backend subscription'); 131 - } 132 - }); 133 - 134 - </script> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="utf-8"> 5 + <title>notifications api</title> 6 + </head> 7 + <body> 8 + <h1>hello!</h1> 9 + <p>this is the api server for <a href="https://spacedust.microcosm.blue/">spacedust</a> demos!</p> 10 + <p>the source code for this server is on github at <a href="https://github.com/at-microcosm/spacedust-utils/tree/main/server">at-microcosm/spacedust-utils</a>.</p> 11 + <h3>demos:</h3> 12 + <ul> 13 + <li> 14 + <p><a href="https://notifications.microcosm.blue">universal atproto notifications</a> with spacedust and webpush</p> 15 + </li> 16 + </ul> 17 + </body> 18 + </html>
-29
server/web-content/service-worker.js
··· 1 - function urlBase64ToUint8Array(base64String) { 2 - var padding = '='.repeat((4 - base64String.length % 4) % 4); 3 - var base64 = (base64String + padding) 4 - .replace(/\-/g, '+') 5 - .replace(/_/g, '/'); 6 - 7 - var rawData = window.atob(base64); 8 - var outputArray = new Uint8Array(rawData.length); 9 - 10 - for (var i = 0; i < rawData.length; ++i) { 11 - outputArray[i] = rawData.charCodeAt(i); 12 - } 13 - return outputArray; 14 - } 15 - 16 - self.addEventListener('push', function(event) { 17 - const { title, body } = event.data.json(); 18 - 19 - // Display notification or handle data 20 - // Example: show a notification 21 - // const title = 'New Notification'; 22 - // const body = event.data.text(); 23 - // const icon = '/images/icon.png'; 24 - // const tag = 'simple-push-demo-notification-tag'; 25 - 26 - event.waitUntil(self.registration.showNotification(title, { body })); 27 - 28 - // TODO: resubscribe to notifs to try to stay alive 29 - });