diff options
Diffstat (limited to 'static/src')
-rw-r--r-- | static/src/assets/api.js | 73 | ||||
-rw-r--r-- | static/src/follow.md | 75 |
2 files changed, 93 insertions, 55 deletions
diff --git a/static/src/assets/api.js b/static/src/assets/api.js new file mode 100644 index 0000000..bec2740 --- /dev/null +++ b/static/src/assets/api.js @@ -0,0 +1,73 @@ + +const doFetch = async (req) => { + let res, jsonRes; + try { + res = await fetch(req); + jsonRes = await res.json(); + + } catch (e) { + + if (e instanceof SyntaxError) + e = new Error(`status ${res.status}, empty (or invalid) response body`); + + console.error(`api call ${req.method} ${req.url}: unexpected error:`, e); + throw e; + } + + if (jsonRes.error) { + console.error( + `api call ${req.method} ${req.url}: application error:`, + res.status, + jsonRes.error, + ); + + throw jsonRes.error; + } + + return jsonRes; +} + +// may throw +const solvePow = async () => { + + const res = await call('GET', '/api/pow/challenge'); + + const worker = new Worker('/assets/solvePow.js'); + + const p = new Promise((resolve, reject) => { + worker.postMessage({seedHex: res.seed, target: res.target}); + worker.onmessage = resolve; + }); + + const powSol = (await p).data; + worker.terminate(); + + return {seed: res.seed, solution: powSol}; +} + +const call = async (method, route, opts = {}) => { + const { body = {}, requiresPow = false } = opts; + + const reqOpts = { method }; + + if (requiresPow) { + const {seed, solution} = await solvePow(); + body.powSeed = seed; + body.powSolution = solution; + } + + if (Object.keys(body).length > 0) { + + const form = new FormData(); + for (const key in body) form.append(key, body[key]); + + reqOpts.body = form; + } + + const req = new Request(route, reqOpts); + return doFetch(req); +} + +export { + call, +} diff --git a/static/src/follow.md b/static/src/follow.md index 4e949dd..b02e7f0 100644 --- a/static/src/follow.md +++ b/static/src/follow.md @@ -4,6 +4,8 @@ title: "Follow the Blog" nofollow: true --- +<script async type="module" src="/assets/api.js"></script> + Here's your options for receiving updates about new blog posts: ## Option 1: Email @@ -40,82 +42,45 @@ is published then input your email below and smash that subscribe button! <span id="emailStatus"></span> <script> + const emailAddress = document.getElementById("emailAddress"); const emailSubscribe = document.getElementById("emailSubscribe"); const emailSubscribeOrigValue = emailSubscribe.value; const emailStatus = document.getElementById("emailStatus"); -const solvePow = async (seedHex, target) => { - - const worker = new Worker('/assets/solvePow.js'); - - const p = new Promise((resolve, reject) => { - worker.postMessage({seedHex, target}); - worker.onmessage = resolve; - }); - - const solutionHex = (await p).data; - worker.terminate(); - - return solutionHex; -} - emailSubscribe.onclick = async () => { + const api = await import("/assets/api.js"); + emailSubscribe.disabled = true; emailSubscribe.className = ""; emailSubscribe.value = "Please hold..."; + emailStatus.innerHTML = ''; - await (async () => { - - setErr = (errStr, retry) => { - emailStatus.className = "fail"; - emailStatus.innerHTML = errStr - if (retry) emailStatus.innerHTML += " (please try again)"; - }; + try { if (!window.isSecureContext) { - setErr("The browser environment is not secure.", false); - return; + throw "The browser environment is not secure."; } - const getPowReq = new Request('/api/pow/challenge'); - const res = await fetch(getPowReq) - .then(response => response.json()) - - if (res.error) { - setErr(res.error, true); - return; - } - - const powSol = await solvePow(res.seed, res.target); - - const subscribeForm = new FormData(); - subscribeForm.append('powSeed', res.seed); - subscribeForm.append('powSolution', powSol); - subscribeForm.append('email', emailAddress.value); - - const subscribeReq = new Request('/api/mailinglist/subscribe', { - method: 'POST', - body: subscribeForm, + await api.call('POST', '/api/mailinglist/subscribe', { + body: { email: emailAddress.value }, + requiresPow: true, }); - const subRes = await fetch(subscribeReq) - .then(response => response.json()); - - if (subRes.error) { - setErr(subRes.error, true); - return; - } - emailStatus.className = "success"; emailStatus.innerHTML = "Verification email sent (check your spam folder)"; - })(); + } catch (e) { + emailStatus.className = "fail"; + emailStatus.innerHTML = e; + + } finally { + emailSubscribe.disabled = false; + emailSubscribe.className = "button-primary"; + emailSubscribe.value = emailSubscribeOrigValue; + } - emailSubscribe.disabled = false; - emailSubscribe.className = "button-primary"; - emailSubscribe.value = emailSubscribeOrigValue; }; </script> |