import * as commonmark from './commonmark.min.js'; function escape(text) { return (text ?? '').replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>'); } function escapeAttribute(text) { return (text ?? '').replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", '''); } export async function get_blog_message(id) { let message; await ssb.sqlAsync( 'SELECT author, timestamp, content FROM messages WHERE id = ?', [id], function(row) { let content = JSON.parse(row.content); message = { author: row.author, timestamp: row.timestamp, blog: content?.blog, title: content?.title, }; }); if (message) { await ssb.sqlAsync( ` SELECT json_extract(content, '$.name') AS name FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'about' AND json_extract(content, '$.about') = author AND name IS NOT NULL ORDER BY sequence DESC LIMIT 1 `, [message.author], function(row) { message.name = row.name; }); } return message; } export function markdown(md) { let reader = new commonmark.Parser({safe: true}); let writer = new commonmark.HtmlRenderer(); let parsed = reader.parse(md || ''); let walker = parsed.walker(); let event, node; while ((event = walker.next())) { node = event.node; if (event.entering) { if (node.destination?.startsWith('&')) { node.destination = '/' + node.destination + '/view?filename=' + node.firstChild?.literal; } else if (node.destination?.startsWith('@') || node.destination?.startsWith('%')) { node.destination = '/~core/ssb/#' + escape(node.destination); } } } return writer.render(parsed); } export async function render_blog_post_html(blog_post) { let blob = utf8Decode(await ssb.blobGet(blog_post.blog)); return ` 🪵Tilde Friends Blog - ${markdown(blog_post.title)}

🪵Tilde Friends Blog

${escape(blog_post.name)} ${escape(new Date(blog_post.timestamp).toString())}
${markdown(blob)}
`; } function render_blog_post(blog_post) { return `

${escape(blog_post.title)}

${escape(blog_post.name)} ${escape(new Date(blog_post.timestamp).toString())}
${markdown(blog_post.summary)}
`; } export function render_html(blogs) { return ` 🪵Tilde Friends Blog

🪵Tilde Friends Blog

atom feed
${blogs.map(blog_post => render_blog_post(blog_post)).join('\n')} `; } function render_blog_post_atom(blog_post) { return ` ${escape(blog_post.title)} ${blog_post.id} ${escape(new Date(blog_post.timestamp).toString())} ${escape(blog_post.summary)} ${escape(blog_post.name)} ${escape(blog_post.author)} `; } export function render_atom(blogs) { return ` 🪵Tilde Blog A subtitle. ${core.url} ${new Date().toString()} ${blogs.map(blog_post => render_blog_post_atom(blog_post)).join('\n')} `; } export async function get_posts() { let blogs = []; let ids = await ssb.getIdentities(); await ssb.sqlAsync(` WITH blogs AS ( SELECT messages.author, messages.id, json_extract(messages.content, '$.title') AS title, json_extract(messages.content, '$.summary') AS summary, json_extract(messages.content, '$.blog') AS blog, messages.timestamp FROM messages_fts('blog') JOIN messages ON messages.rowid = messages_fts.rowid WHERE json_extract(messages.content, '$.type') = 'blog'), public AS ( SELECT author FROM ( SELECT messages.author, RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, json_extract(messages.content, '$.publicWebHosting') AS is_public FROM messages_fts('about') JOIN messages ON messages.rowid = messages_fts.rowid WHERE json_extract(messages.content, '$.type') = 'about' AND is_public IS NOT NULL) WHERE author_rank = 1 AND is_public), names AS ( SELECT author, name FROM ( SELECT messages.author, RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, json_extract(messages.content, '$.name') AS name FROM messages_fts('about') JOIN messages ON messages.rowid = messages_fts.rowid WHERE json_extract(messages.content, '$.type') = 'about' AND json_extract(messages.content, '$.about') = messages.author AND name IS NOT NULL) WHERE author_rank = 1) SELECT blogs.*, names.name FROM blogs JOIN json_each(?) AS self ON self.value = blogs.author JOIN public ON public.author = blogs.author LEFT OUTER JOIN names ON names.author = blogs.author ORDER BY blogs.timestamp DESC LIMIT 20 `, [JSON.stringify(ids)], function(row) { blogs.push(row); }); return blogs; }