this repo has no description

initial /astral scafold

vielle.dev ccc39113 1567a67b

verified
+470
+3
package.json
··· 10 "lexgen": "lex-cli generate" 11 }, 12 "dependencies": { 13 "@atcute/client": "^4.2.1", 14 "@atcute/identity-resolver": "^1.2.2", 15 "@atcute/lexicons": "^1.2.6", 16 "@atcute/oauth-browser-client": "^2.0.3", 17 "actor-typeahead": "^0.1.2",
··· 10 "lexgen": "lex-cli generate" 11 }, 12 "dependencies": { 13 + "@atcute/atproto": "^3.1.10", 14 "@atcute/client": "^4.2.1", 15 + "@atcute/identity": "^1.1.3", 16 "@atcute/identity-resolver": "^1.2.2", 17 + "@atcute/identity-resolver-node": "^1.0.3", 18 "@atcute/lexicons": "^1.2.6", 19 "@atcute/oauth-browser-client": "^2.0.3", 20 "actor-typeahead": "^0.1.2",
+28
pnpm-lock.yaml
··· 8 9 .: 10 dependencies: 11 '@atcute/client': 12 specifier: ^4.2.1 13 version: 4.2.1 14 '@atcute/identity-resolver': 15 specifier: ^1.2.2 16 version: 1.2.2(@atcute/identity@1.1.3) 17 '@atcute/lexicons': 18 specifier: ^1.2.6 19 version: 1.2.6 ··· 50 resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} 51 engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} 52 53 '@atcute/car@5.0.0': 54 resolution: {integrity: sha512-OIY2xTXv8lSpZsDSn/UYQtJSMvDw5Hi4Q+uyvmiqSM+fht08QRAEq/nxa5YFciPZ3nfDFnZ3//EgJw7QhkSXLQ==} 55 ··· 64 65 '@atcute/crypto@2.3.0': 66 resolution: {integrity: sha512-w5pkJKCjbNMQu+F4JRHbR3ROQyhi1wbn+GSC6WDQamcYHkZmEZk1/eoI354bIQOOfkEM6aFLv718iskrkon4GQ==} 67 68 '@atcute/identity-resolver@1.2.2': 69 resolution: {integrity: sha512-eUh/UH4bFvuXS0X7epYCeJC/kj4rbBXfSRumLEH4smMVwNOgTo7cL/0Srty+P/qVPoZEyXdfEbS0PHJyzoXmHw==} ··· 1686 transitivePeerDependencies: 1687 - supports-color 1688 1689 '@atcute/car@5.0.0': 1690 dependencies: 1691 '@atcute/cbor': 2.2.8 ··· 1714 '@atcute/multibase': 1.1.6 1715 '@atcute/uint8array': 1.0.6 1716 '@noble/secp256k1': 3.0.0 1717 1718 '@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3)': 1719 dependencies:
··· 8 9 .: 10 dependencies: 11 + '@atcute/atproto': 12 + specifier: ^3.1.10 13 + version: 3.1.10 14 '@atcute/client': 15 specifier: ^4.2.1 16 version: 4.2.1 17 + '@atcute/identity': 18 + specifier: ^1.1.3 19 + version: 1.1.3 20 '@atcute/identity-resolver': 21 specifier: ^1.2.2 22 version: 1.2.2(@atcute/identity@1.1.3) 23 + '@atcute/identity-resolver-node': 24 + specifier: ^1.0.3 25 + version: 1.0.3(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3) 26 '@atcute/lexicons': 27 specifier: ^1.2.6 28 version: 1.2.6 ··· 59 resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} 60 engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} 61 62 + '@atcute/atproto@3.1.10': 63 + resolution: {integrity: sha512-+GKZpOc0PJcdWMQEkTfg/rSNDAAHxmAUGBl60g2az15etqJn5WaUPNGFE2sB7hKpwi5Ue2h/L0OacINcE/JDDQ==} 64 + 65 '@atcute/car@5.0.0': 66 resolution: {integrity: sha512-OIY2xTXv8lSpZsDSn/UYQtJSMvDw5Hi4Q+uyvmiqSM+fht08QRAEq/nxa5YFciPZ3nfDFnZ3//EgJw7QhkSXLQ==} 67 ··· 76 77 '@atcute/crypto@2.3.0': 78 resolution: {integrity: sha512-w5pkJKCjbNMQu+F4JRHbR3ROQyhi1wbn+GSC6WDQamcYHkZmEZk1/eoI354bIQOOfkEM6aFLv718iskrkon4GQ==} 79 + 80 + '@atcute/identity-resolver-node@1.0.3': 81 + resolution: {integrity: sha512-RPH5M4ZRayKRcGnJWUOPVhN5WSYURXXZxKzgVT9lj/WZCH6ij2Vg3P3Eva7GGs0SG1ytnX1XVBTMoIk8nF/SLQ==} 82 + peerDependencies: 83 + '@atcute/identity': ^1.0.0 84 + '@atcute/identity-resolver': ^1.0.0 85 86 '@atcute/identity-resolver@1.2.2': 87 resolution: {integrity: sha512-eUh/UH4bFvuXS0X7epYCeJC/kj4rbBXfSRumLEH4smMVwNOgTo7cL/0Srty+P/qVPoZEyXdfEbS0PHJyzoXmHw==} ··· 1704 transitivePeerDependencies: 1705 - supports-color 1706 1707 + '@atcute/atproto@3.1.10': 1708 + dependencies: 1709 + '@atcute/lexicons': 1.2.6 1710 + 1711 '@atcute/car@5.0.0': 1712 dependencies: 1713 '@atcute/cbor': 2.2.8 ··· 1736 '@atcute/multibase': 1.1.6 1737 '@atcute/uint8array': 1.0.6 1738 '@noble/secp256k1': 3.0.0 1739 + 1740 + '@atcute/identity-resolver-node@1.0.3(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3)': 1741 + dependencies: 1742 + '@atcute/identity': 1.1.3 1743 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.3) 1744 + '@atcute/lexicons': 1.2.6 1745 1746 '@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3)': 1747 dependencies:
+217
src/pages/astral/[user].astro
···
··· 1 + --- 2 + export const prerender = false; 3 + import { getPdsEndpoint, isAtprotoDid } from "@atcute/identity"; 4 + import { isHandle } from "@atcute/lexicons/syntax"; 5 + import Base from "../../Base.astro"; 6 + 7 + // slug user to pds 8 + const { user } = Astro.params; 9 + if (!user) 10 + return new Response("", { 11 + status: 308, 12 + headers: { 13 + Location: "/astral", 14 + }, 15 + }); 16 + const actor = (isAtprotoDid(user) || isHandle(user)) && user; 17 + if (!actor) 18 + return new Response( 19 + `<h1><code>${user}</code> is not a valid identifier</h1><p>Head to <a href="/">home</a> or <a href="/astral">astral powers</a></p>`, 20 + { 21 + status: 400, 22 + headers: { 23 + "Content-Type": "text/html", 24 + }, 25 + } 26 + ); 27 + --- 28 + 29 + <Base title={actor}> 30 + <script set:html={`window.actor = "${actor}";`} /> 31 + <script> 32 + import { Client, simpleFetchHandler } from "@atcute/client"; 33 + import { 34 + normalPowers, 35 + parentPowers, 36 + powerData, 37 + powers, 38 + type powerId, 39 + } from "../../consts/astral"; 40 + import { DevVielleDndAstral } from "../../lexicons"; 41 + import { 42 + CompositeDidDocumentResolver, 43 + CompositeHandleResolver, 44 + DohJsonHandleResolver, 45 + LocalActorResolver, 46 + PlcDidDocumentResolver, 47 + WebDidDocumentResolver, 48 + WellKnownHandleResolver, 49 + } from "@atcute/identity-resolver"; 50 + 51 + const actor = 52 + "actor" in window 53 + ? (window.actor as 54 + | undefined 55 + | `did:plc:${string}` 56 + | `did:web:${string}` 57 + | `${string}.${string}`) 58 + : undefined; 59 + if (!actor) throw "loaded without actor in window. missing `window.actor`"; 60 + 61 + const actorResolver = new LocalActorResolver({ 62 + handleResolver: new CompositeHandleResolver({ 63 + methods: { 64 + dns: new DohJsonHandleResolver({ 65 + dohUrl: "https://mozilla.cloudflare-dns.com/dns-query", 66 + }), 67 + http: new WellKnownHandleResolver(), 68 + }, 69 + }), 70 + didDocumentResolver: new CompositeDidDocumentResolver({ 71 + methods: { 72 + plc: new PlcDidDocumentResolver(), 73 + web: new WebDidDocumentResolver(), 74 + }, 75 + }), 76 + }); 77 + 78 + const doc = await actorResolver 79 + .resolve(actor) 80 + .catch((err) => console.error(err)); 81 + if (!doc) { 82 + document.body.innerText = 83 + "<p>Failed to resolve user. Check browser console for more info</p>"; 84 + throw ""; 85 + } 86 + 87 + const client = new Client({ 88 + handler: simpleFetchHandler({ service: doc.pds }), 89 + }); 90 + 91 + const res = await client 92 + .get("com.atproto.repo.getRecord", { 93 + params: { 94 + repo: doc.did, 95 + collection: "dev.vielle.dnd.astral", 96 + rkey: "self", 97 + }, 98 + }) 99 + .then((res) => 100 + res.ok 101 + ? res.data.value 102 + : (() => { 103 + throw res.data; 104 + })() 105 + ) 106 + .then( 107 + async (res) => 108 + await DevVielleDndAstral.mainSchema["~standard"].validate(res) 109 + ) 110 + .then((res) => 111 + !res.issues 112 + ? res.value 113 + : (() => { 114 + throw res.issues; 115 + })() 116 + ) 117 + .catch((err) => { 118 + console.error(err); 119 + return null; 120 + }); 121 + 122 + const isValidPowers = 123 + (res?.powers.reduce( 124 + (acc, curr) => 125 + acc && 126 + curr !== "dev.vielle.dnd.power#invalid" && 127 + curr !== "dev.vielle.dnd.power#locked", 128 + true 129 + ) && 130 + res?.powers.reduce( 131 + (acc, curr) => 132 + acc && 133 + parentPowers[curr].reduce( 134 + (acc, curr) => acc && res.powers.includes(curr), 135 + true 136 + ), 137 + true 138 + ) && 139 + res?.points >= res?.powers.length) ?? 140 + false; 141 + 142 + // custom render 143 + console.log(res, isValidPowers); 144 + if (res) { 145 + const powerUl = document.createElement("dl"); 146 + powerUl.append( 147 + ...(res?.powers 148 + .map((x) => 149 + normalPowers.includes(x as (typeof normalPowers)[number]) 150 + ? (x as powerId) 151 + : powers.INVALID 152 + ) 153 + .map( 154 + (x) => [x, powerData[x]] as [powerId, (typeof powerData)[powerId]] 155 + ) 156 + .map(([id, data]) => { 157 + const dt = document.createElement("dt"); 158 + const dd = document.createElement("dd"); 159 + const dl = document.createElement("dl"); 160 + 161 + console.log(id, data); 162 + 163 + dt.innerText = data.name; 164 + 165 + console.log(id, data); 166 + 167 + const description = [ 168 + document.createElement("dt"), 169 + document.createElement("dd"), 170 + ]; 171 + description[0].innerText = "description"; 172 + description[1].innerText = data.description; 173 + 174 + const img: [HTMLElement, HTMLElement, HTMLImageElement] = [ 175 + document.createElement("dt"), 176 + document.createElement("dd"), 177 + document.createElement("img"), 178 + ]; 179 + img[0].innerText = "Image"; 180 + img[2].src = data.image.src; 181 + img[2].alt = data.image.alt; 182 + img[1].append(img.pop() ?? ""); 183 + 184 + const meta = [ 185 + document.createElement("dt"), 186 + document.createElement("dd"), 187 + document.createElement("dl"), 188 + ]; 189 + meta[0].innerText = "Meta"; 190 + meta[2].append( 191 + ...data.meta 192 + .map((x) => { 193 + const res = [ 194 + document.createElement("dt"), 195 + document.createElement("dd"), 196 + ]; 197 + res[0].innerText = x.name; 198 + res[1].innerText = x.value; 199 + return res; 200 + }) 201 + .flat() 202 + ); 203 + meta[1].append(meta.pop() ?? ""); 204 + 205 + dl.append(...description, ...img, ...meta); 206 + 207 + dd.append(dl); 208 + return [dt, dd]; 209 + }) 210 + .flat() ?? []) 211 + ); 212 + document.body.prepend(powerUl); 213 + } else { 214 + document.body.append("No data for user"); 215 + } 216 + </script> 217 + </Base>
+222
src/pages/astral/index.astro
···
··· 1 + --- 2 + import Base from "../../Base.astro"; 3 + --- 4 + 5 + <Base title="Astral Powers"> 6 + <style> 7 + :global(dt) { 8 + font-weight: bold; 9 + } 10 + 11 + :global(.power) { 12 + border-left: 1px solid white; 13 + padding-inline-start: 10px; 14 + } 15 + </style> 16 + <script> 17 + import "@atcute/atproto"; 18 + import { getAuth } from "../../lib/auth"; 19 + import { 20 + parentPowers, 21 + powerTree, 22 + powerData, 23 + powers, 24 + type powerId, 25 + normalPowers, 26 + } from "../../consts/astral"; 27 + import { DevVielleDndAstral } from "../../lexicons"; 28 + const [client, session, did] = await getAuth(true); 29 + 30 + const res = await client 31 + .get("com.atproto.repo.getRecord", { 32 + params: { 33 + repo: did, 34 + collection: "dev.vielle.dnd.astral", 35 + rkey: "self", 36 + }, 37 + }) 38 + .then((res) => 39 + res.ok 40 + ? res.data.value 41 + : (() => { 42 + throw res.data; 43 + })() 44 + ) 45 + .then( 46 + async (res) => 47 + await DevVielleDndAstral.mainSchema["~standard"].validate(res) 48 + ) 49 + .then((res) => 50 + !res.issues 51 + ? res.value 52 + : (() => { 53 + throw res.issues; 54 + })() 55 + ) 56 + .catch((err) => { 57 + console.error(err); 58 + return null; 59 + }); 60 + 61 + const isValidPowers = 62 + (res?.powers.reduce( 63 + (acc, curr) => 64 + acc && 65 + curr !== "dev.vielle.dnd.power#invalid" && 66 + curr !== "dev.vielle.dnd.power#locked", 67 + true 68 + ) && 69 + res?.powers.reduce( 70 + (acc, curr) => 71 + acc && 72 + parentPowers[curr].reduce( 73 + (acc, curr) => acc && res.powers.includes(curr), 74 + true 75 + ), 76 + true 77 + ) && 78 + res?.points >= res?.powers.length) ?? 79 + false; 80 + 81 + // custom render 82 + console.log(res, isValidPowers); 83 + 84 + const renderPower = (power: typeof powerTree) => { 85 + const li = document.createElement("li"); 86 + const dl = document.createElement("dl"); 87 + dl.classList.add("power"); 88 + li.append(dl); 89 + 90 + if (power.id === powers.LOCKED) { 91 + dl.innerHTML = `<dt>Status</dt><dd>Locked</dd>`; 92 + return li; 93 + } 94 + 95 + const name = [document.createElement("dt"), document.createElement("dd")]; 96 + name[0].innerText = "name"; 97 + name[1].innerText = powerData[power.id].name; 98 + 99 + const description = [ 100 + document.createElement("dt"), 101 + document.createElement("dd"), 102 + ]; 103 + description[0].innerText = "description"; 104 + description[1].innerText = powerData[power.id].description; 105 + 106 + const img: [HTMLElement, HTMLElement, HTMLImageElement] = [ 107 + document.createElement("dt"), 108 + document.createElement("dd"), 109 + document.createElement("img"), 110 + ]; 111 + img[0].innerText = "Image"; 112 + img[2].src = powerData[power.id].image.src; 113 + img[2].alt = powerData[power.id].image.alt; 114 + img[1].append(img.pop() ?? ""); 115 + 116 + const meta = [ 117 + document.createElement("dt"), 118 + document.createElement("dd"), 119 + document.createElement("dl"), 120 + ]; 121 + meta[0].innerText = "Meta"; 122 + meta[2].append( 123 + ...powerData[power.id].meta 124 + .map((x) => { 125 + const res = [ 126 + document.createElement("dt"), 127 + document.createElement("dd"), 128 + ]; 129 + res[0].innerText = x.name; 130 + res[1].innerText = x.value; 131 + return res; 132 + }) 133 + .flat() 134 + ); 135 + meta[1].append(meta.pop() ?? ""); 136 + 137 + const children = [ 138 + document.createElement("dt"), 139 + document.createElement("dd"), 140 + document.createElement("ul"), 141 + ]; 142 + children[0].innerText = "children"; 143 + children[2].append(...power.children.map(renderPower)); 144 + children[1].append(children.pop() ?? ""); 145 + 146 + dl.append(...name, ...img, ...description, ...meta, ...children); 147 + 148 + return li; 149 + }; 150 + 151 + const ul = document.createElement("ul"); 152 + ul.append(renderPower(powerTree)); 153 + document.body.append(ul); 154 + 155 + const powerUl = document.createElement("dl"); 156 + powerUl.append( 157 + ...(res?.powers 158 + .map((x) => 159 + normalPowers.includes(x as (typeof normalPowers)[number]) 160 + ? (x as powerId) 161 + : powers.INVALID 162 + ) 163 + .map((x) => [x, powerData[x]] as [powerId, (typeof powerData)[powerId]]) 164 + .map(([id, data]) => { 165 + const dt = document.createElement("dt"); 166 + const dd = document.createElement("dd"); 167 + const dl = document.createElement("dl"); 168 + 169 + console.log(id, data); 170 + 171 + dt.innerText = data.name; 172 + 173 + console.log(id, data); 174 + 175 + const description = [ 176 + document.createElement("dt"), 177 + document.createElement("dd"), 178 + ]; 179 + description[0].innerText = "description"; 180 + description[1].innerText = data.description; 181 + 182 + const img: [HTMLElement, HTMLElement, HTMLImageElement] = [ 183 + document.createElement("dt"), 184 + document.createElement("dd"), 185 + document.createElement("img"), 186 + ]; 187 + img[0].innerText = "Image"; 188 + img[2].src = data.image.src; 189 + img[2].alt = data.image.alt; 190 + img[1].append(img.pop() ?? ""); 191 + 192 + const meta = [ 193 + document.createElement("dt"), 194 + document.createElement("dd"), 195 + document.createElement("dl"), 196 + ]; 197 + meta[0].innerText = "Meta"; 198 + meta[2].append( 199 + ...data.meta 200 + .map((x) => { 201 + const res = [ 202 + document.createElement("dt"), 203 + document.createElement("dd"), 204 + ]; 205 + res[0].innerText = x.name; 206 + res[1].innerText = x.value; 207 + return res; 208 + }) 209 + .flat() 210 + ); 211 + meta[1].append(meta.pop() ?? ""); 212 + 213 + dl.append(...description, ...img, ...meta); 214 + 215 + dd.append(dl); 216 + return [dt, dd]; 217 + }) 218 + .flat() ?? []) 219 + ); 220 + document.body.prepend(powerUl); 221 + </script> 222 + </Base>