AT Protocol OAuth template in Deno, Hono, HTMX
17
fork

Configure Feed

Select the types of activity you want to include in your feed.

Revert "define qa lexicons, init utils"

This reverts commit 1282b02f765f2b79379e82b71dd0b665468e54de.

zeudev e572bd92 1282b02f

+48 -158
-1
.env.example
··· 1 - BASE_URL=<`http://127.0.0.1:8000` or `https://pedro.vote`> 2 1 COOKIE_SECRET=<`openssl rand -base64 64`>
+4 -12
README.md
··· 1 - # Pedro 2 - ### Ask questions, share opinions, vote together 3 - 4 - ## Feature Roadmap (WIP) 5 - - [ ] Question and Answers (~stackoverflow.com) 6 - - [ ] Upvote answers 7 - - [ ] Asker can highlight helpful answers 8 - - [ ] Poll 9 - - [ ] Single vs multiple choice 10 - - [ ] Live updates 11 - - [ ] Consensus (~pol.is) 12 - - [ ] Third-parties can add opinions 1 + # AT Protocol OAuth Template 2 + ### for Deno, Hono, and HTMX 13 3 14 4 ## Getting Started 15 5 1. Set up `.env` file with a `COOKIE_SECRET` variable ··· 27 17 - [`Hono`](https://hono.dev) - Web application framework 28 18 - [`HTMX`](https://htmx.org) - AJAX library 29 19 - [`@tijs/atproto-oauth`](https://jsr.io/@tijs/atproto-oauth) - AT Protocol OAuth library 20 + 21 + _Source hosted on [Tangled](https://tangled.org/zeu.dev/atproto-oauth-deno), mirrored on [GitHub](https://github.com/zeucapua/atproto-oauth-deno-demo)_
-41
lexicons/vote/pedro/qa/answer.json
··· 1 - { 2 - "lexicon": 1, 3 - "$type": "com.atproto.lexicon.schema", 4 - "id": "vote.pedro.qa.answer", 5 - "defs": { 6 - "main": { 7 - "description": "A user generated answer to a referenced question", 8 - "key": "tid", 9 - "type": "record", 10 - "record": { 11 - "type": "object", 12 - "required": [ 13 - "description", 14 - "question", 15 - "createdAt" 16 - ], 17 - "properties": { 18 - "description": { 19 - "type": "string" 20 - }, 21 - "facets": { 22 - "type": "array", 23 - "items": { 24 - "type": "ref", 25 - "ref": "app.bsky.richtext.facet" 26 - }, 27 - "description": "Annotations of text (mentions, URLs, etc.) for the description" 28 - }, 29 - "question": { 30 - "type": "ref", 31 - "ref": "com.atproto.repo.strongRef" 32 - }, 33 - "createdAt": { 34 - "type": "string", 35 - "format": "datetime" 36 - } 37 - } 38 - } 39 - } 40 - } 41 - }
-54
lexicons/vote/pedro/qa/question.json
··· 1 - { 2 - "lexicon": 1, 3 - "$type": "com.atproto.lexicon.schema", 4 - "id": "vote.pedro.qa.question", 5 - "defs": { 6 - "main": { 7 - "description": "A user generated question that others can answer to", 8 - "key": "tid", 9 - "type": "record", 10 - "record": { 11 - "type": "object", 12 - "required": [ 13 - "title", 14 - "createdAt" 15 - ], 16 - "properties": { 17 - "title": { 18 - "type": "string", 19 - "minLength": 1, 20 - "maxLength": 150 21 - }, 22 - "description": { 23 - "type": "string" 24 - }, 25 - "facets": { 26 - "type": "array", 27 - "items": { 28 - "type": "ref", 29 - "ref": "app.bsky.richtext.facet" 30 - }, 31 - "description": "Annotations of text (mentions, URLs, etc.) for the description" 32 - }, 33 - "tags": { 34 - "type": "array", 35 - "items": { 36 - "type": "string" 37 - } 38 - }, 39 - "createdAt": { 40 - "type": "string", 41 - "format": "datetime" 42 - }, 43 - "highlightedAnswers": { 44 - "type": "array", 45 - "items": { 46 - "type": "ref", 47 - "ref": "com.atproto.repo.strongRef" 48 - } 49 - } 50 - } 51 - } 52 - } 53 - } 54 - }
-29
lexicons/vote/pedro/qa/upvote.json
··· 1 - { 2 - "lexicon": 1, 3 - "$type": "com.atproto.lexicon.schema", 4 - "id": "vote.pedro.qa.upvote", 5 - "defs": { 6 - "main": { 7 - "description": "An upvote to a question or answer", 8 - "key": "tid", 9 - "type": "record", 10 - "record": { 11 - "type": "object", 12 - "required": [ 13 - "reference", 14 - "createdAt" 15 - ], 16 - "properties": { 17 - "reference": { 18 - "type": "ref", 19 - "ref": "com.atproto.repo.strongRef" 20 - }, 21 - "createdAt": { 22 - "type": "string", 23 - "format": "datetime" 24 - } 25 - } 26 - } 27 - } 28 - } 29 - }
+44 -4
main.tsx
··· 6 6 const app = new Hono(); 7 7 8 8 export const oauth = createATProtoOAuth({ 9 - baseUrl: Deno.env.get("BASE_URL")!, 10 - appName: "Pedro", 9 + baseUrl: "https://atproto-oauth-deno-demo.zeu.deno.net", // or for local dev: "http://127.0.0.1:8000/", 10 + appName: "AT Protocol OAuth Example App", 11 11 cookieSecret: Deno.env.get("COOKIE_SECRET")!, 12 12 storage: new MemoryStorage(), 13 13 sessionTtl: 60 * 60 * 24 * 14, // 14 days ··· 32 32 app.get("/", (c) => { 33 33 return c.html( 34 34 <SiteLayout context={c}> 35 - <h1>Pedro</h1> 36 - <p>Ask questions, share opinions, vote together</p> 35 + <h1>AT Protocol OAuth Template</h1> 36 + <h3>for Deno, Hono, and HTMX</h3> 37 + 38 + <hr /> 39 + 40 + <h2>Getting Started</h2> 41 + <ol> 42 + <li> 43 + <div style={{ display: "flex", "flex-direction": "column", gap: "0.25em" }}> 44 + <p>Set up <code>.env</code> file with a <code>COOKIE_SECRET</code> variable</p> 45 + <code style={{ background: "lightgray", padding: "1em", width: "fit-content" }}> 46 + COOKIE_SECRET=[run `openssl rand -base64 64` in the terminal] 47 + </code> 48 + </div> 49 + </li> 50 + 51 + <li> 52 + <div style={{ display: "flex", "flex-direction": "column", gap: "0.25em" }}> 53 + <p>Run the web application</p> 54 + <code style={{ background: "lightgray", padding: "1em", width: "fit-content" }}> 55 + deno task start 56 + </code> 57 + </div> 58 + </li> 59 + </ol> 60 + 61 + <hr /> 62 + 63 + <h2>Packages</h2> 64 + <ul> 65 + <li><a href="https://deno.com">Deno</a> - Runtime and package manager</li> 66 + <li><a href="https://hono.dev">Hono</a> - Web application framework</li> 67 + <li><a href="https://htmx.org">HTMX</a> - AJAX library</li> 68 + <li> 69 + <a href="https://jsr.io/@tijs/atproto-oauth">@tijs/atproto-oauth</a> - AT Protocol OAuth library 70 + </li> 71 + </ul> 72 + 73 + <p style={{ "font-style": "italic" }}> 74 + Source hosted on <a href="https://tangled.org/zeu.dev/atproto-oauth-deno">Tangled</a> 75 + , mirrored on <a href="https://github.com/zeucapua/atproto-oauth-deno-demo">GitHub</a> 76 + </p> 37 77 </SiteLayout> 38 78 ) 39 79 });
-17
utils.ts
··· 1 - import { SessionInterface } from "@tijs/atproto-oauth"; 2 - 3 - type Record<T> = { 4 - uri: string; 5 - cid: string; 6 - value: T 7 - } 8 - 9 - export async function listRecords<T>(session: SessionInterface, nsid: string) { 10 - const response = await session.makeRequest( 11 - "GET", 12 - `${session.pdsUrl}/xrpc/com.atproto.repo.listRecords?repo=${session.did}&collection=${encodeURIComponent(nsid)}` 13 - ); 14 - 15 - const { records } = await response.json(); 16 - return records as Record<T>[]; 17 - }