an attempt to make a lightweight, easily self-hostable, scoped bluesky appview
1import { setupAuth, getAuthenticatedDid, authVerifier } from "./utils/auth.ts";
2import { setupSystemDb } from "./utils/dbsystem.ts";
3import { didDocument } from "./utils/diddoc.ts";
4import { cachedFetch, searchParamsToJson, withCors } from "./utils/server.ts";
5import { ViewServer, ViewServerConfig } from "./viewserver.ts";
6import { extractDid } from "./utils/identity.ts";
7import { config } from "./config.ts";
8import { compile, devWatch } from "./shared-landing/build.ts";
9let { js, html, css } = await compile("view");
10
11// ------------------------------------------
12// AppView Setup
13// ------------------------------------------
14
15setupAuth({
16 serviceDid: config.viewServer.did,
17 //keyCacheSize: 500,
18 //keyCacheTTL: 10 * 60 * 1000,
19});
20
21const viewServerConfig: ViewServerConfig = {
22 baseDbPath: "./dbs/view/registered-users", // The directory for user databases
23 systemDbPath: "./dbs/view/registered-users/system.db", // The path for the main system database
24};
25export const genericViewServer = new ViewServer(viewServerConfig);
26setupSystemDb(genericViewServer.systemDB);
27
28// add me lol
29genericViewServer.systemDB.exec(`
30 INSERT OR IGNORE INTO users (did, role, registrationdate, onboardingstatus)
31 VALUES (
32 'did:plc:mn45tewwnse5btfftvd3powc',
33 'admin',
34 datetime('now'),
35 'ready'
36 );
37
38 INSERT OR IGNORE INTO users (did, role, registrationdate, onboardingstatus)
39 VALUES (
40 'did:web:did12.whey.party',
41 'admin',
42 datetime('now'),
43 'ready'
44 );
45`);
46
47genericViewServer.start();
48
49// ------------------------------------------
50// XRPC Method Implementations
51// ------------------------------------------
52
53Deno.serve(
54 { port: config.viewServer.port },
55 async (req: Request): Promise<Response> => {
56 const url = new URL(req.url);
57 const pathname = url.pathname;
58 const searchParams = searchParamsToJson(url.searchParams);
59
60 if (html && js) {
61 if (pathname === "/" || pathname === "") {
62 return new Response(html, {
63 headers: withCors({ "content-type": "text/html; charset=utf-8" }),
64 });
65 }
66 if (pathname === "/landing-view.js") {
67 return new Response(js, {
68 headers: withCors({
69 "content-type": "application/javascript; charset=utf-8",
70 }),
71 });
72 }
73 } else {
74 if (pathname === "/" || pathname === "") {
75 return new Response(`server is compiling your webpage. loading...`, {
76 headers: withCors({ "content-type": "text/html; charset=utf-8" }),
77 });
78 }
79 }
80 if (pathname === "/app.css") {
81 return new Response(css, {
82 headers: withCors({
83 "content-type": "text/css; charset=utf-8",
84 }),
85 });
86 }
87
88 if (pathname === "/.well-known/did.json") {
89 return new Response(
90 JSON.stringify(
91 didDocument(
92 "view",
93 config.viewServer.did,
94 config.viewServer.host,
95 "whatever"
96 )
97 ),
98 {
99 headers: withCors({ "Content-Type": "application/json" }),
100 }
101 );
102 }
103 if (pathname === "/health") {
104 return new Response("OK", {
105 status: 200,
106 headers: withCors({
107 "Content-Type": "text/plain",
108 }),
109 });
110 }
111 if (req.method === "OPTIONS") {
112 return new Response(null, {
113 status: 204,
114 headers: {
115 "Access-Control-Allow-Origin": "*",
116 "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
117 "Access-Control-Allow-Headers": "*",
118 },
119 });
120 }
121 console.log(`request for "${pathname}"`);
122 return await genericViewServer.viewServerHandler(req);
123 }
124);
125
126
127devWatch("view", ({ js: newjs, html: newhtml, css: newcss }) => {
128 js = newjs;
129 html = newhtml;
130 css = newcss;
131});