| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | let g_hash; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function query(sql, params) { | 
					
						
							|  |  |  | 	let results = []; | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | 	await ssb.sqlAsync(sql, params, function (row) { | 
					
						
							| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | 		results.push(row); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	return results; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function resolve(id) { | 
					
						
							|  |  |  | 	try { | 
					
						
							|  |  |  | 		let blob = await ssb.blobGet(id); | 
					
						
							|  |  |  | 		if (blob) { | 
					
						
							|  |  |  | 			let json; | 
					
						
							|  |  |  | 			try { | 
					
						
							|  |  |  | 				json = JSON.parse(utf8Decode(blob)); | 
					
						
							|  |  |  | 			} catch { | 
					
						
							|  |  |  | 				return {id: utf8Decode(blob)}; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (json?.links) { | 
					
						
							|  |  |  | 				for (let [key, value] of Object.entries(json.links)) { | 
					
						
							|  |  |  | 					json.links[key] = await resolve(value); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return json; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return 'huh?' + json; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return `missing<${id}>`; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} catch (e) { | 
					
						
							|  |  |  | 		return id + ': ' + e.message; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function get_names(identities) { | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | 	return Object.fromEntries( | 
					
						
							|  |  |  | 		( | 
					
						
							|  |  |  | 			await query( | 
					
						
							|  |  |  | 				`
 | 
					
						
							| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | 		SELECT author, name FROM ( | 
					
						
							|  |  |  | 			SELECT | 
					
						
							|  |  |  | 				messages.author, | 
					
						
							|  |  |  | 				RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, | 
					
						
							|  |  |  | 				messages.content ->> 'name' AS name | 
					
						
							|  |  |  | 			FROM messages | 
					
						
							|  |  |  | 			JOIN json_each(?) AS identities ON identities.value = messages.author | 
					
						
							|  |  |  | 			WHERE | 
					
						
							|  |  |  | 				json_extract(messages.content, '$.type') = 'about' AND | 
					
						
							|  |  |  | 				content ->> 'about' = messages.author AND name IS NOT NULL) | 
					
						
							|  |  |  | 		WHERE author_rank = 1 | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | 	`,
 | 
					
						
							|  |  |  | 				[JSON.stringify(identities)] | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		).map((x) => [x.author, x.name]) | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function render(hash) { | 
					
						
							|  |  |  | 	g_hash = hash; | 
					
						
							|  |  |  | 	if (!hash) { | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | 		let sites = await query( | 
					
						
							|  |  |  | 			`
 | 
					
						
							| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | 			SELECT site.author, site.id | 
					
						
							|  |  |  | 			FROM messages site | 
					
						
							|  |  |  | 			WHERE site.content ->> 'type' = 'web-init' | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | 		`,
 | 
					
						
							|  |  |  | 			[] | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 		let names = await get_names(sites.map((x) => x.author)); | 
					
						
							| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | 		if (hash === g_hash) { | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | 			await app.setDocument( | 
					
						
							|  |  |  | 				`<ul style="background-color: #ddd">${sites.map((x) => `<li><a target="_top" href="#${encodeURIComponent(x.id)}">${names[x.author] ?? x.author} - ${x.id}</a></li>`).join('\n')}</ul>` | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | 		let site_id = | 
					
						
							|  |  |  | 			hash.charAt(0) == '#' | 
					
						
							|  |  |  | 				? decodeURIComponent(hash.substring(1)) | 
					
						
							|  |  |  | 				: decodeURIComponent(hash); | 
					
						
							| 
									
										
										
										
											2025-04-02 18:07:25 -04:00
										 |  |  | 		await app.setDocument(`<html style="margin: 0; padding: 0; width: 100vw; height: 100vh; margin: 0; padding: 0">
 | 
					
						
							|  |  |  | 			<body style="display: flex; flex-direction: column; width: 100vw; height: 100vh"> | 
					
						
							|  |  |  | 				<iframe src="${encodeURIComponent(site_id)}/index.html" style="flex: 1 1; border: 0; background-color: #fff"></iframe> | 
					
						
							|  |  |  | 			</body> | 
					
						
							|  |  |  | 		</html>`); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | core.register('message', async function message_handler(message) { | 
					
						
							|  |  |  | 	if (message.event == 'hashChange') { | 
					
						
							|  |  |  | 		await render(message.hash); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function main() { | 
					
						
							|  |  |  | 	render(null); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-05 22:05:26 -04:00
										 |  |  | main(); |