grain.social is a photo sharing platform built on atproto.

support local infra with a local pds + plc + jetstream

+8 -1
.env.example
··· 1 1 BFF_DATABASE_URL=grain.db 2 2 BFF_PRIVATE_KEY_1= 3 3 BFF_PRIVATE_KEY_2= 4 - BFF_PRIVATE_KEY_3= 4 + BFF_PRIVATE_KEY_3= 5 + 6 + # If running local infra 7 + USE_CDN=false 8 + DENO_TLS_CA_STORE=system 9 + BFF_PLC_DIRECTORY_URL=https://plc.dev.grain.social 10 + BFF_JETSTREAM_URL=https://jetstream.dev.grain.social 11 + PDS_HOST_URL=https://pds.dev.grain.social
+2 -1
.gitignore
··· 3 3 .DS_Store 4 4 *.fly.toml 5 5 image_storage 6 - .env 6 + .env 7 + grain-root.crt
+93
README.md
··· 58 58 deno run dev 59 59 ``` 60 60 61 + ### Running the whole infra locally PDS + PLC + Jetstream 62 + 63 + You must ensure that pds.dev.grain.social resolves to your local machine 64 + (typically 127.0.0.1 or your Docker host). 65 + 66 + #### Add to /etc/hosts (macOS/Linux) 67 + 68 + ```bash 69 + sudo nano /etc/hosts 70 + ``` 71 + 72 + ```bash 73 + 127.0.0.1 pds.dev.grain.social 74 + 127.0.0.1 plc.dev.grain.social 75 + 127.0.0.1 jetstream.dev.grain.social 76 + ``` 77 + 78 + #### Start services 79 + 80 + ```bash 81 + cd local-infra 82 + docker compose up -d 83 + ``` 84 + 85 + #### Install the Root Certificate on Host 86 + 87 + First, get your Caddy container ID: 88 + 89 + ```bash 90 + docker ps 91 + ``` 92 + 93 + Then copy the cert out: 94 + 95 + ```bash 96 + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain grain-root.crt 97 + ``` 98 + 99 + Once you have grain-root.crt, install it: 100 + 101 + macOS: 102 + 103 + ```bash 104 + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain grain-root.crt 105 + ``` 106 + 107 + Ubuntu/Linux: 108 + 109 + ```bash 110 + sudo cp grain-root.crt /usr/local/share/ca-certificates/grain.crt 111 + sudo update-ca-certificates 112 + ``` 113 + 114 + #### Update ENV Variables 115 + 116 + Make sure the following env vars are in your .env 117 + 118 + ```bash 119 + # for running local infra only 120 + DENO_TLS_CA_STORE=system 121 + USE_CDN=false 122 + BFF_PLC_DIRECTORY_URL=https://plc.dev.grain.social 123 + BFF_JETSTREAM_URL=https://jetstream.dev.grain.social 124 + PDS_HOST_URL=https://pds.dev.grain.social 125 + ``` 126 + 127 + #### Run the app 128 + 129 + Start the app: 130 + 131 + ```bash 132 + deno run dev 133 + ``` 134 + 135 + You can then create an account via the "Create Account" button in the navbar. 136 + 137 + After clicking the link, verify you are redirected to 138 + `https://pds.dev.grain.social/...` 139 + 140 + Create an account with your desired handle. 141 + 142 + If all goes well you will be redirectly to the app at 143 + `http://localhost:8080/onboard` and prompted to edit your profile details. 144 + 145 + From then on, you can login by typing `https://pds.dev.grain.social` into the 146 + login input and follow the PDS prompts to login. 147 + 148 + NOTE: When running with local-infra, only blobs on the local PDS will get 149 + resolved because of the PLC directory. All of the other images will appear 150 + broken. We could do some more work to support both but seems fine for now to 151 + test new features. Just switch back to non local-infra mode and you'll see them 152 + all. 153 + 61 154 ## License 62 155 63 156 [MIT License](LICENSE)
+4 -1
deno.json
··· 2 2 "imports": { 3 3 "$lexicon/": "./__generated__/", 4 4 "@atproto/syntax": "npm:@atproto/syntax@^0.4.0", 5 - "@bigmoves/bff": "jsr:@bigmoves/bff@0.3.0-beta.25", 5 + "@bigmoves/bff": "jsr:@bigmoves/bff@0.3.0-beta.27", 6 6 "@gfx/canvas": "jsr:@gfx/canvas@^0.5.8", 7 7 "@std/path": "jsr:@std/path@^1.0.9", 8 8 "@tailwindcss/cli": "npm:@tailwindcss/cli@^4.1.4", ··· 12 12 "tailwindcss": "npm:tailwindcss@^4.1.4", 13 13 "typed-htmx": "npm:typed-htmx@^0.3.1" 14 14 }, 15 + "patch": [ 16 + "../bff/packages/bff" 17 + ], 15 18 "tasks": { 16 19 "start": "deno run -A --unstable-kv --unstable-ffi ./src/main.tsx", 17 20 "dev": "deno run \"dev:*\"",
+26 -631
deno.lock
··· 2 2 "version": "5", 3 3 "specifiers": { 4 4 "jsr:@bigmoves/atproto-oauth-client@0.2": "0.2.0", 5 - "jsr:@bigmoves/bff@0.3.0-beta.25": "0.3.0-beta.25", 6 - "jsr:@deno/gfm@0.10": "0.10.0", 7 - "jsr:@denosaurs/emoji@0.3": "0.3.1", 8 - "jsr:@denosaurs/plug@1": "1.0.5", 9 - "jsr:@denosaurs/plug@1.0.5": "1.0.5", 10 - "jsr:@gfx/canvas@~0.5.8": "0.5.8", 11 - "jsr:@std/assert@0.214": "0.214.0", 12 - "jsr:@std/assert@0.217": "0.217.0", 13 - "jsr:@std/assert@^1.0.12": "1.0.13", 14 5 "jsr:@std/assert@^1.0.13": "1.0.13", 15 - "jsr:@std/async@^1.0.12": "1.0.12", 16 - "jsr:@std/cli@^1.0.17": "1.0.17", 17 - "jsr:@std/data-structures@^1.0.6": "1.0.7", 18 - "jsr:@std/encoding@0.214": "0.214.0", 19 - "jsr:@std/encoding@0.217.0": "0.217.0", 6 + "jsr:@std/cli@^1.0.18": "1.0.18", 20 7 "jsr:@std/encoding@^1.0.10": "1.0.10", 21 - "jsr:@std/fmt@0.214": "0.214.0", 22 8 "jsr:@std/fmt@^1.0.8": "1.0.8", 23 - "jsr:@std/fs@0.214": "0.214.0", 24 - "jsr:@std/fs@0.217.0": "0.217.0", 25 - "jsr:@std/fs@^1.0.16": "1.0.17", 26 9 "jsr:@std/html@^1.0.4": "1.0.4", 27 - "jsr:@std/http@^1.0.13": "1.0.16", 28 - "jsr:@std/internal@^1.0.6": "1.0.7", 10 + "jsr:@std/http@^1.0.13": "1.0.17", 11 + "jsr:@std/internal@^1.0.6": "1.0.8", 29 12 "jsr:@std/media-types@^1.1.0": "1.1.0", 30 13 "jsr:@std/net@^1.0.4": "1.0.4", 31 - "jsr:@std/path@0.214": "0.214.0", 32 - "jsr:@std/path@0.217": "0.217.0", 33 - "jsr:@std/path@0.217.0": "0.217.0", 34 - "jsr:@std/path@^1.0.8": "1.0.9", 35 - "jsr:@std/path@^1.0.9": "1.0.9", 14 + "jsr:@std/path@^1.0.8": "1.1.0", 15 + "jsr:@std/path@^1.0.9": "1.1.0", 16 + "jsr:@std/path@^1.1.0": "1.1.0", 36 17 "jsr:@std/streams@^1.0.9": "1.0.9", 37 - "jsr:@std/testing@^1.0.11": "1.0.11", 38 18 "npm:@atproto-labs/handle-resolver-node@~0.1.14": "0.1.15", 39 - "npm:@atproto-labs/simple-store@~0.1.2": "0.1.2", 40 - "npm:@atproto/api@~0.14.19": "0.14.22", 41 19 "npm:@atproto/api@~0.15.7": "0.15.7", 42 20 "npm:@atproto/common@~0.4.10": "0.4.11", 43 21 "npm:@atproto/identity@~0.4.7": "0.4.8", 44 22 "npm:@atproto/jwk@0.1.4": "0.1.4", 45 - "npm:@atproto/lex-cli@*": "0.8.1", 46 23 "npm:@atproto/lexicon@*": "0.4.11", 47 - "npm:@atproto/lexicon@~0.4.10": "0.4.11", 48 24 "npm:@atproto/lexicon@~0.4.11": "0.4.11", 49 25 "npm:@atproto/oauth-client@~0.3.13": "0.3.16", 50 - "npm:@atproto/oauth-types@~0.2.4": "0.2.7", 51 26 "npm:@atproto/syntax@0.4": "0.4.0", 52 27 "npm:@atproto/xrpc-server@*": "0.7.18", 53 28 "npm:@tailwindcss/cli@*": "4.1.7", 54 - "npm:@tailwindcss/cli@^4.0.12": "4.1.7", 55 - "npm:@tailwindcss/cli@^4.1.3": "4.1.7", 56 29 "npm:@tailwindcss/cli@^4.1.4": "4.1.7", 57 - "npm:@types/node@*": "22.15.15", 58 30 "npm:clsx@^2.1.1": "2.1.1", 59 31 "npm:date-fns@^4.1.0": "4.1.0", 60 - "npm:github-slugger@2": "2.0.0", 61 - "npm:he@^1.2.0": "1.2.0", 62 32 "npm:jose@5.9.6": "5.9.6", 63 - "npm:katex@0.16": "0.16.22", 64 - "npm:marked-alert@2": "2.1.2_marked@12.0.2", 65 - "npm:marked-footnote@^1.2.0": "1.2.4_marked@12.0.2", 66 - "npm:marked-gfm-heading-id@^3.1.0": "3.2.0_marked@12.0.2", 67 - "npm:marked@12": "12.0.2", 68 33 "npm:multiformats@*": "13.3.4", 69 34 "npm:multiformats@^13.3.2": "13.3.4", 70 35 "npm:popmotion@^11.0.5": "11.0.5", 71 36 "npm:preact-render-to-string@^6.5.13": "6.5.13_preact@10.26.6", 72 37 "npm:preact@^10.26.5": "10.26.6", 73 - "npm:prismjs@^1.29.0": "1.30.0", 74 - "npm:sanitize-html@^2.13.0": "2.17.0", 75 - "npm:sharp@~0.34.1": "0.34.1", 76 38 "npm:tailwind-merge@^3.2.0": "3.3.0", 77 - "npm:tailwindcss@^4.0.12": "4.1.7", 78 - "npm:tailwindcss@^4.1.3": "4.1.7", 79 39 "npm:tailwindcss@^4.1.4": "4.1.7", 80 40 "npm:typed-htmx@~0.3.1": "0.3.1" 81 41 }, ··· 84 44 "integrity": "5c3ca124dd52eff51dace83790779ebe48c4b41559b799e16c8750bd415f2124", 85 45 "dependencies": [ 86 46 "npm:@atproto-labs/handle-resolver-node", 87 - "npm:@atproto-labs/simple-store", 88 47 "npm:@atproto/jwk", 89 48 "npm:@atproto/oauth-client", 90 - "npm:@atproto/oauth-types", 91 49 "npm:jose" 92 50 ] 93 51 }, ··· 99 57 "npm:tailwind-merge" 100 58 ] 101 59 }, 102 - "@bigmoves/bff@0.3.0-beta.25": { 103 - "integrity": "33a71b4d3f8e28832f2caa13dd09fbf799c5142509e16ce934bc4757509b4a3d", 104 - "dependencies": [ 105 - "jsr:@bigmoves/atproto-oauth-client", 106 - "jsr:@std/assert@^1.0.13", 107 - "jsr:@std/fmt@^1.0.8", 108 - "jsr:@std/http", 109 - "jsr:@std/path@^1.0.8", 110 - "npm:@atproto/api@~0.15.7", 111 - "npm:@atproto/common", 112 - "npm:@atproto/identity", 113 - "npm:@atproto/lexicon@~0.4.11", 114 - "npm:@atproto/oauth-client", 115 - "npm:@atproto/syntax", 116 - "npm:clsx", 117 - "npm:multiformats@^13.3.2", 118 - "npm:preact", 119 - "npm:preact-render-to-string", 120 - "npm:tailwind-merge" 121 - ] 122 - }, 123 - "@deno/gfm@0.10.0": { 124 - "integrity": "51708205e3559a4aeb6afb29d07c5bfafe7941f91bb360351ef6621de9a39527", 125 - "dependencies": [ 126 - "jsr:@denosaurs/emoji", 127 - "npm:github-slugger", 128 - "npm:he", 129 - "npm:katex", 130 - "npm:marked", 131 - "npm:marked-alert", 132 - "npm:marked-footnote", 133 - "npm:marked-gfm-heading-id", 134 - "npm:prismjs", 135 - "npm:sanitize-html" 136 - ] 137 - }, 138 - "@denosaurs/emoji@0.3.1": { 139 - "integrity": "b0aed5f55dec99e83da7c9637fe0a36d1d6252b7c99deaaa3fc5dea3fcf3da8b" 140 - }, 141 - "@denosaurs/plug@1.0.5": { 142 - "integrity": "04cd988da558adc226202d88c3a434d5fcc08146eaf4baf0cea0c2284b16d2bf", 143 - "dependencies": [ 144 - "jsr:@std/encoding@0.214", 145 - "jsr:@std/fmt@0.214", 146 - "jsr:@std/fs@0.214", 147 - "jsr:@std/path@0.214" 148 - ] 149 - }, 150 - "@gfx/canvas@0.5.8": { 151 - "integrity": "a61c80292528e7433d428556b494a0ea496dd8e6abd4a338b8b25fc04e46ea3e", 152 - "dependencies": [ 153 - "jsr:@denosaurs/plug@1", 154 - "jsr:@denosaurs/plug@1.0.5", 155 - "jsr:@std/encoding@0.217.0", 156 - "jsr:@std/fs@0.217.0", 157 - "jsr:@std/path@0.217.0" 158 - ] 159 - }, 160 - "@std/assert@0.214.0": { 161 - "integrity": "55d398de76a9828fd3b1aa653f4dba3eee4c6985d90c514865d2be9bd082b140" 162 - }, 163 - "@std/assert@0.217.0": { 164 - "integrity": "c98e279362ca6982d5285c3b89517b757c1e3477ee9f14eb2fdf80a45aaa9642" 165 - }, 166 60 "@std/assert@1.0.13": { 167 61 "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", 168 62 "dependencies": [ 169 63 "jsr:@std/internal" 170 64 ] 171 65 }, 172 - "@std/async@1.0.12": { 173 - "integrity": "d1bfcec459e8012846fe4e38dfc4241ab23240ecda3d8d6dfcf6d81a632e803d" 174 - }, 175 - "@std/cli@1.0.17": { 176 - "integrity": "e15b9abe629e17be90cc6216327f03a29eae613365f1353837fa749aad29ce7b" 177 - }, 178 - "@std/data-structures@1.0.7": { 179 - "integrity": "16932d2c8d281f65eaaa2209af2473209881e33b1ced54cd1b015e7b4cdbb0d2" 180 - }, 181 - "@std/encoding@0.214.0": { 182 - "integrity": "30a8713e1db22986c7e780555ffd2fefd1d4f9374d734bb41f5970f6c3352af5" 183 - }, 184 - "@std/encoding@0.217.0": { 185 - "integrity": "b03e8ff94c98d6b6a02c02c5cf8e5d203400155516248964fc4559abc04669dc" 66 + "@std/cli@1.0.18": { 67 + "integrity": "33846eab6a7cac52156cc105a798451df06965693606e4668adfe0436a155fd7" 186 68 }, 187 69 "@std/encoding@1.0.10": { 188 70 "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" 189 71 }, 190 - "@std/fmt@0.214.0": { 191 - "integrity": "40382cff88a0783b347b4d69b94cf931ab8e549a733916718cb866c08efac4d4" 192 - }, 193 72 "@std/fmt@1.0.8": { 194 73 "integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7" 195 74 }, 196 - "@std/fs@0.214.0": { 197 - "integrity": "bc880fea0be120cb1550b1ed7faf92fe071003d83f2456a1e129b39193d85bea", 198 - "dependencies": [ 199 - "jsr:@std/assert@0.214", 200 - "jsr:@std/path@0.214" 201 - ] 202 - }, 203 - "@std/fs@0.217.0": { 204 - "integrity": "0bfff5f3618d68c385b28b4ffbf3a15c98293a0f1186444458b62e0111ce77b2", 205 - "dependencies": [ 206 - "jsr:@std/assert@0.217", 207 - "jsr:@std/path@0.217" 208 - ] 209 - }, 210 - "@std/fs@1.0.17": { 211 - "integrity": "1c00c632677c1158988ef7a004cb16137f870aafdb8163b9dce86ec652f3952b", 212 - "dependencies": [ 213 - "jsr:@std/path@^1.0.9" 214 - ] 215 - }, 216 75 "@std/html@1.0.4": { 217 76 "integrity": "eff3497c08164e6ada49b7f81a28b5108087033823153d065e3f89467dd3d50e" 218 77 }, 219 - "@std/http@1.0.16": { 220 - "integrity": "80c8d08c4bfcf615b89978dcefb84f7e880087cf3b6b901703936f3592a06933", 78 + "@std/http@1.0.17": { 79 + "integrity": "98aec8ab4080d95c21f731e3008f69c29c5012d12f1b4e553f85935db601569f", 221 80 "dependencies": [ 222 81 "jsr:@std/cli", 223 - "jsr:@std/encoding@^1.0.10", 224 - "jsr:@std/fmt@^1.0.8", 82 + "jsr:@std/encoding", 83 + "jsr:@std/fmt", 225 84 "jsr:@std/html", 226 85 "jsr:@std/media-types", 227 86 "jsr:@std/net", 228 - "jsr:@std/path@^1.0.9", 87 + "jsr:@std/path@^1.1.0", 229 88 "jsr:@std/streams" 230 89 ] 231 90 }, 232 - "@std/internal@1.0.7": { 233 - "integrity": "39eeb5265190a7bc5d5591c9ff019490bd1f2c3907c044a11b0d545796158a0f" 91 + "@std/internal@1.0.8": { 92 + "integrity": "fc66e846d8d38a47cffd274d80d2ca3f0de71040f855783724bb6b87f60891f5" 234 93 }, 235 94 "@std/media-types@1.1.0": { 236 95 "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" ··· 238 97 "@std/net@1.0.4": { 239 98 "integrity": "2f403b455ebbccf83d8a027d29c5a9e3a2452fea39bb2da7f2c04af09c8bc852" 240 99 }, 241 - "@std/path@0.214.0": { 242 - "integrity": "d5577c0b8d66f7e8e3586d864ebdf178bb326145a3611da5a51c961740300285", 243 - "dependencies": [ 244 - "jsr:@std/assert@0.214" 245 - ] 246 - }, 247 - "@std/path@0.217.0": { 248 - "integrity": "1217cc25534bca9a2f672d7fe7c6f356e4027df400c0e85c0ef3e4343bc67d11", 249 - "dependencies": [ 250 - "jsr:@std/assert@0.217" 251 - ] 252 - }, 253 - "@std/path@1.0.9": { 254 - "integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e" 100 + "@std/path@1.1.0": { 101 + "integrity": "ddc94f8e3c275627281cbc23341df6b8bcc874d70374f75fec2533521e3d6886" 255 102 }, 256 103 "@std/streams@1.0.9": { 257 104 "integrity": "a9d26b1988cdd7aa7b1f4b51e1c36c1557f3f252880fa6cc5b9f37078b1a5035" 258 - }, 259 - "@std/testing@1.0.11": { 260 - "integrity": "12b3db12d34f0f385a26248933bde766c0f8c5ad8b6ab34d4d38f528ab852f48", 261 - "dependencies": [ 262 - "jsr:@std/assert@^1.0.12", 263 - "jsr:@std/async", 264 - "jsr:@std/data-structures", 265 - "jsr:@std/fs@^1.0.16", 266 - "jsr:@std/internal", 267 - "jsr:@std/path@^1.0.8" 268 - ] 269 105 } 270 106 }, 271 107 "npm": { ··· 281 117 "dependencies": [ 282 118 "@atproto-labs/fetch", 283 119 "@atproto-labs/pipe", 284 - "@atproto-labs/simple-store@0.2.0", 120 + "@atproto-labs/simple-store", 285 121 "@atproto-labs/simple-store-memory", 286 122 "@atproto/did", 287 123 "zod" ··· 314 150 "@atproto-labs/handle-resolver@0.1.8": { 315 151 "integrity": "sha512-Y0ckccoCGDo/3g4thPkgp9QcORmc+qqEaCBCYCZYtfLIQp4775u22wd+4fyEyJP4DqoReKacninkICgRGfs3dQ==", 316 152 "dependencies": [ 317 - "@atproto-labs/simple-store@0.2.0", 153 + "@atproto-labs/simple-store", 318 154 "@atproto-labs/simple-store-memory", 319 155 "@atproto/did", 320 156 "zod" ··· 334 170 "@atproto-labs/simple-store-memory@0.1.3": { 335 171 "integrity": "sha512-jkitT9+AtU+0b28DoN92iURLaCt/q/q4yX8q6V+9LSwYlUTqKoj/5NFKvF7x6EBuG+gpUdlcycbH7e60gjOhRQ==", 336 172 "dependencies": [ 337 - "@atproto-labs/simple-store@0.2.0", 173 + "@atproto-labs/simple-store", 338 174 "lru-cache" 339 175 ] 340 176 }, 341 - "@atproto-labs/simple-store@0.1.2": { 342 - "integrity": "sha512-9vTNvyPPBs44tKVFht16wGlilW8u4wpEtKwLkWbuNEh3h9TTQ8zjVhEoGZh/v73G4Otr9JUOSIq+/5+8OZD2mQ==" 343 - }, 344 177 "@atproto-labs/simple-store@0.2.0": { 345 178 "integrity": "sha512-0bRbAlI8Ayh03wRwncAMEAyUKtZ+AuTS1jgPrfym1WVOAOiottI/ZmgccqLl6w5MbxVcClNQF7WYGKvGwGoIhA==" 346 179 }, 347 - "@atproto/api@0.14.22": { 348 - "integrity": "sha512-ziXPau+sUdFovObSnsoN7JbOmUw1C5e5L28/yXf3P8vbEnSS3HVVGD1jYcscBYY34xQqi4bVDpwMYx/4yRsTuQ==", 349 - "dependencies": [ 350 - "@atproto/common-web", 351 - "@atproto/lexicon", 352 - "@atproto/syntax", 353 - "@atproto/xrpc@0.6.12", 354 - "await-lock", 355 - "multiformats@9.9.0", 356 - "tlds", 357 - "zod" 358 - ] 359 - }, 360 180 "@atproto/api@0.15.7": { 361 181 "integrity": "sha512-YRETLcOwDCYfGs7Sl9ObqPwhOlVWrPkw4f1AYGIrXLQS58WHe/vz1lZbqOqMsC6gvCnyZnOuKlhsRHZ14rBLzg==", 362 182 "dependencies": [ 363 183 "@atproto/common-web", 364 184 "@atproto/lexicon", 365 185 "@atproto/syntax", 366 - "@atproto/xrpc@0.7.0", 186 + "@atproto/xrpc", 367 187 "await-lock", 368 188 "multiformats@9.9.0", 369 189 "tlds", ··· 425 245 "zod" 426 246 ] 427 247 }, 428 - "@atproto/lex-cli@0.8.1": { 429 - "integrity": "sha512-0Ns6kX46gum2jU8bpvWCSVqoYhjmJrOGR/NLfLHgPbJtBlyxMGQAxqpy1x6zOi6SkkRGWYhHvRfr5J8lTHbxjA==", 430 - "dependencies": [ 431 - "@atproto/lexicon", 432 - "@atproto/syntax", 433 - "chalk", 434 - "commander@9.5.0", 435 - "prettier", 436 - "ts-morph", 437 - "yesno", 438 - "zod" 439 - ], 440 - "bin": true 441 - }, 442 248 "@atproto/lexicon@0.4.11": { 443 249 "integrity": "sha512-btefdnvNz2Ao2I+qbmj0F06HC8IlrM/IBz6qOBS50r0S6uDf5tOO+Mv2tSVdimFkdzyDdLtBI1sV36ONxz2cOw==", 444 250 "dependencies": [ ··· 456 262 "@atproto-labs/fetch", 457 263 "@atproto-labs/handle-resolver", 458 264 "@atproto-labs/identity-resolver", 459 - "@atproto-labs/simple-store@0.2.0", 265 + "@atproto-labs/simple-store", 460 266 "@atproto-labs/simple-store-memory", 461 267 "@atproto/did", 462 268 "@atproto/jwk@0.1.5", 463 269 "@atproto/oauth-types", 464 - "@atproto/xrpc@0.7.0", 270 + "@atproto/xrpc", 465 271 "multiformats@9.9.0", 466 272 "zod" 467 273 ] ··· 482 288 "@atproto/common", 483 289 "@atproto/crypto", 484 290 "@atproto/lexicon", 485 - "@atproto/xrpc@0.7.0", 291 + "@atproto/xrpc", 486 292 "cbor-x", 487 293 "express", 488 294 "http-errors", ··· 493 299 "zod" 494 300 ] 495 301 }, 496 - "@atproto/xrpc@0.6.12": { 497 - "integrity": "sha512-Ut3iISNLujlmY9Gu8sNU+SPDJDvqlVzWddU8qUr0Yae5oD4SguaUFjjhireMGhQ3M5E0KljQgDbTmnBo1kIZ3w==", 498 - "dependencies": [ 499 - "@atproto/lexicon", 500 - "zod" 501 - ] 502 - }, 503 302 "@atproto/xrpc@0.7.0": { 504 303 "integrity": "sha512-SfhP9dGx2qclaScFDb58Jnrmim5nk4geZXCqg6sB0I/KZhZEkr9iIx1hLCp+sxkIfEsmEJjeWO4B0rjUIJW5cw==", 505 304 "dependencies": [ ··· 556 355 "tslib@2.8.1" 557 356 ] 558 357 }, 559 - "@img/sharp-darwin-arm64@0.34.1": { 560 - "integrity": "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==", 561 - "optionalDependencies": [ 562 - "@img/sharp-libvips-darwin-arm64" 563 - ], 564 - "os": ["darwin"], 565 - "cpu": ["arm64"] 566 - }, 567 - "@img/sharp-darwin-x64@0.34.1": { 568 - "integrity": "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==", 569 - "optionalDependencies": [ 570 - "@img/sharp-libvips-darwin-x64" 571 - ], 572 - "os": ["darwin"], 573 - "cpu": ["x64"] 574 - }, 575 - "@img/sharp-libvips-darwin-arm64@1.1.0": { 576 - "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==", 577 - "os": ["darwin"], 578 - "cpu": ["arm64"] 579 - }, 580 - "@img/sharp-libvips-darwin-x64@1.1.0": { 581 - "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==", 582 - "os": ["darwin"], 583 - "cpu": ["x64"] 584 - }, 585 - "@img/sharp-libvips-linux-arm64@1.1.0": { 586 - "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==", 587 - "os": ["linux"], 588 - "cpu": ["arm64"] 589 - }, 590 - "@img/sharp-libvips-linux-arm@1.1.0": { 591 - "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==", 592 - "os": ["linux"], 593 - "cpu": ["arm"] 594 - }, 595 - "@img/sharp-libvips-linux-ppc64@1.1.0": { 596 - "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", 597 - "os": ["linux"], 598 - "cpu": ["ppc64"] 599 - }, 600 - "@img/sharp-libvips-linux-s390x@1.1.0": { 601 - "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==", 602 - "os": ["linux"], 603 - "cpu": ["s390x"] 604 - }, 605 - "@img/sharp-libvips-linux-x64@1.1.0": { 606 - "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==", 607 - "os": ["linux"], 608 - "cpu": ["x64"] 609 - }, 610 - "@img/sharp-libvips-linuxmusl-arm64@1.1.0": { 611 - "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==", 612 - "os": ["linux"], 613 - "cpu": ["arm64"] 614 - }, 615 - "@img/sharp-libvips-linuxmusl-x64@1.1.0": { 616 - "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==", 617 - "os": ["linux"], 618 - "cpu": ["x64"] 619 - }, 620 - "@img/sharp-linux-arm64@0.34.1": { 621 - "integrity": "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==", 622 - "optionalDependencies": [ 623 - "@img/sharp-libvips-linux-arm64" 624 - ], 625 - "os": ["linux"], 626 - "cpu": ["arm64"] 627 - }, 628 - "@img/sharp-linux-arm@0.34.1": { 629 - "integrity": "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==", 630 - "optionalDependencies": [ 631 - "@img/sharp-libvips-linux-arm" 632 - ], 633 - "os": ["linux"], 634 - "cpu": ["arm"] 635 - }, 636 - "@img/sharp-linux-s390x@0.34.1": { 637 - "integrity": "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==", 638 - "optionalDependencies": [ 639 - "@img/sharp-libvips-linux-s390x" 640 - ], 641 - "os": ["linux"], 642 - "cpu": ["s390x"] 643 - }, 644 - "@img/sharp-linux-x64@0.34.1": { 645 - "integrity": "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==", 646 - "optionalDependencies": [ 647 - "@img/sharp-libvips-linux-x64" 648 - ], 649 - "os": ["linux"], 650 - "cpu": ["x64"] 651 - }, 652 - "@img/sharp-linuxmusl-arm64@0.34.1": { 653 - "integrity": "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==", 654 - "optionalDependencies": [ 655 - "@img/sharp-libvips-linuxmusl-arm64" 656 - ], 657 - "os": ["linux"], 658 - "cpu": ["arm64"] 659 - }, 660 - "@img/sharp-linuxmusl-x64@0.34.1": { 661 - "integrity": "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==", 662 - "optionalDependencies": [ 663 - "@img/sharp-libvips-linuxmusl-x64" 664 - ], 665 - "os": ["linux"], 666 - "cpu": ["x64"] 667 - }, 668 - "@img/sharp-wasm32@0.34.1": { 669 - "integrity": "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==", 670 - "dependencies": [ 671 - "@emnapi/runtime" 672 - ], 673 - "cpu": ["wasm32"] 674 - }, 675 - "@img/sharp-win32-ia32@0.34.1": { 676 - "integrity": "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==", 677 - "os": ["win32"], 678 - "cpu": ["ia32"] 679 - }, 680 - "@img/sharp-win32-x64@0.34.1": { 681 - "integrity": "sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==", 682 - "os": ["win32"], 683 - "cpu": ["x64"] 684 - }, 685 358 "@ipld/dag-cbor@7.0.3": { 686 359 "integrity": "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA==", 687 360 "dependencies": [ ··· 940 613 ], 941 614 "scripts": true 942 615 }, 943 - "@ts-morph/common@0.25.0": { 944 - "integrity": "sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==", 945 - "dependencies": [ 946 - "minimatch", 947 - "path-browserify", 948 - "tinyglobby" 949 - ] 950 - }, 951 616 "@tybys/wasm-util@0.9.0": { 952 617 "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", 953 618 "dependencies": [ 954 619 "tslib@2.8.1" 955 620 ] 956 621 }, 957 - "@types/node@22.15.15": { 958 - "integrity": "sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==", 959 - "dependencies": [ 960 - "undici-types" 961 - ] 962 - }, 963 622 "abort-controller@3.0.0": { 964 623 "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 965 624 "dependencies": [ ··· 973 632 "negotiator" 974 633 ] 975 634 }, 976 - "ansi-styles@4.3.0": { 977 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 978 - "dependencies": [ 979 - "color-convert" 980 - ] 981 - }, 982 635 "array-flatten@1.1.1": { 983 636 "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 984 637 }, ··· 987 640 }, 988 641 "await-lock@2.2.2": { 989 642 "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==" 990 - }, 991 - "balanced-match@1.0.2": { 992 - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 993 643 }, 994 644 "base64-js@1.5.1": { 995 645 "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" ··· 1009 659 "raw-body", 1010 660 "type-is", 1011 661 "unpipe" 1012 - ] 1013 - }, 1014 - "brace-expansion@2.0.1": { 1015 - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1016 - "dependencies": [ 1017 - "balanced-match" 1018 662 ] 1019 663 }, 1020 664 "braces@3.0.3": { ··· 1072 716 "cborg@1.10.2": { 1073 717 "integrity": "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug==", 1074 718 "bin": true 1075 - }, 1076 - "chalk@4.1.2": { 1077 - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1078 - "dependencies": [ 1079 - "ansi-styles", 1080 - "supports-color" 1081 - ] 1082 719 }, 1083 720 "chownr@3.0.0": { 1084 721 "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==" ··· 1086 723 "clsx@2.1.1": { 1087 724 "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" 1088 725 }, 1089 - "code-block-writer@13.0.3": { 1090 - "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==" 1091 - }, 1092 - "color-convert@2.0.1": { 1093 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1094 - "dependencies": [ 1095 - "color-name" 1096 - ] 1097 - }, 1098 - "color-name@1.1.4": { 1099 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 1100 - }, 1101 - "color-string@1.9.1": { 1102 - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", 1103 - "dependencies": [ 1104 - "color-name", 1105 - "simple-swizzle" 1106 - ] 1107 - }, 1108 - "color@4.2.3": { 1109 - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", 1110 - "dependencies": [ 1111 - "color-convert", 1112 - "color-string" 1113 - ] 1114 - }, 1115 - "commander@8.3.0": { 1116 - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" 1117 - }, 1118 - "commander@9.5.0": { 1119 - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==" 1120 - }, 1121 726 "content-disposition@0.5.4": { 1122 727 "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 1123 728 "dependencies": [ ··· 1142 747 "ms@2.0.0" 1143 748 ] 1144 749 }, 1145 - "deepmerge@4.3.1": { 1146 - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" 1147 - }, 1148 750 "depd@2.0.0": { 1149 751 "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 1150 752 }, ··· 1158 760 "detect-libc@2.0.4": { 1159 761 "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==" 1160 762 }, 1161 - "dom-serializer@2.0.0": { 1162 - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", 1163 - "dependencies": [ 1164 - "domelementtype", 1165 - "domhandler", 1166 - "entities" 1167 - ] 1168 - }, 1169 - "domelementtype@2.3.0": { 1170 - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" 1171 - }, 1172 - "domhandler@5.0.3": { 1173 - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", 1174 - "dependencies": [ 1175 - "domelementtype" 1176 - ] 1177 - }, 1178 - "domutils@3.2.2": { 1179 - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", 1180 - "dependencies": [ 1181 - "dom-serializer", 1182 - "domelementtype", 1183 - "domhandler" 1184 - ] 1185 - }, 1186 763 "dunder-proto@1.0.1": { 1187 764 "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", 1188 765 "dependencies": [ ··· 1207 784 "tapable" 1208 785 ] 1209 786 }, 1210 - "entities@4.5.0": { 1211 - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" 1212 - }, 1213 787 "es-define-property@1.0.1": { 1214 788 "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" 1215 789 }, ··· 1224 798 }, 1225 799 "escape-html@1.0.3": { 1226 800 "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 1227 - }, 1228 - "escape-string-regexp@4.0.0": { 1229 - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" 1230 801 }, 1231 802 "etag@1.8.1": { 1232 803 "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" ··· 1276 847 "fast-redact@3.5.0": { 1277 848 "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==" 1278 849 }, 1279 - "fdir@6.4.4_picomatch@4.0.2": { 1280 - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", 1281 - "dependencies": [ 1282 - "picomatch@4.0.2" 1283 - ], 1284 - "optionalPeers": [ 1285 - "picomatch@4.0.2" 1286 - ] 1287 - }, 1288 850 "fill-range@7.1.1": { 1289 851 "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 1290 852 "dependencies": [ ··· 1340 902 "es-object-atoms" 1341 903 ] 1342 904 }, 1343 - "github-slugger@2.0.0": { 1344 - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" 1345 - }, 1346 905 "gopd@1.2.0": { 1347 906 "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" 1348 907 }, ··· 1352 911 "graphemer@1.4.0": { 1353 912 "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" 1354 913 }, 1355 - "has-flag@4.0.0": { 1356 - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 1357 - }, 1358 914 "has-symbols@1.1.0": { 1359 915 "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" 1360 916 }, ··· 1364 920 "function-bind" 1365 921 ] 1366 922 }, 1367 - "he@1.2.0": { 1368 - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1369 - "bin": true 1370 - }, 1371 923 "hey-listen@1.0.8": { 1372 924 "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" 1373 925 }, 1374 - "htmlparser2@8.0.2": { 1375 - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", 1376 - "dependencies": [ 1377 - "domelementtype", 1378 - "domhandler", 1379 - "domutils", 1380 - "entities" 1381 - ] 1382 - }, 1383 926 "http-errors@2.0.0": { 1384 927 "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 1385 928 "dependencies": [ ··· 1408 951 "ipaddr.js@2.2.0": { 1409 952 "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==" 1410 953 }, 1411 - "is-arrayish@0.3.2": { 1412 - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" 1413 - }, 1414 954 "is-extglob@2.1.1": { 1415 955 "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" 1416 956 }, ··· 1423 963 "is-number@7.0.0": { 1424 964 "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" 1425 965 }, 1426 - "is-plain-object@5.0.0": { 1427 - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" 1428 - }, 1429 966 "iso-datestring-validator@2.2.2": { 1430 967 "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==" 1431 968 }, ··· 1436 973 "jose@5.9.6": { 1437 974 "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==" 1438 975 }, 1439 - "katex@0.16.22": { 1440 - "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", 1441 - "dependencies": [ 1442 - "commander@8.3.0" 1443 - ], 1444 - "bin": true 1445 - }, 1446 976 "lightningcss-darwin-arm64@1.30.1": { 1447 977 "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", 1448 978 "os": ["darwin"], ··· 1520 1050 "@jridgewell/sourcemap-codec" 1521 1051 ] 1522 1052 }, 1523 - "marked-alert@2.1.2_marked@12.0.2": { 1524 - "integrity": "sha512-EFNRZ08d8L/iEIPLTlQMDjvwIsj03gxWCczYTht6DCiHJIZhMk4NK5gtPY9UqAYb09eV5VGT+jD4lp396E0I+w==", 1525 - "dependencies": [ 1526 - "marked" 1527 - ] 1528 - }, 1529 - "marked-footnote@1.2.4_marked@12.0.2": { 1530 - "integrity": "sha512-DB2Kl+wFh6YwZd70qABMY6WUkG1UuyqoNTFoDfGyG79Pz24neYtLBkB+45a7o72V7gkfvbC3CGzIYFobxfMT1Q==", 1531 - "dependencies": [ 1532 - "marked" 1533 - ] 1534 - }, 1535 - "marked-gfm-heading-id@3.2.0_marked@12.0.2": { 1536 - "integrity": "sha512-Xfxpr5lXLDLY10XqzSCA9l2dDaiabQUgtYM9hw8yunyVsB/xYBRpiic6BOiY/EAJw1ik1eWr1ET1HKOAPZBhXg==", 1537 - "dependencies": [ 1538 - "github-slugger", 1539 - "marked" 1540 - ] 1541 - }, 1542 - "marked@12.0.2": { 1543 - "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", 1544 - "bin": true 1545 - }, 1546 1053 "math-intrinsics@1.1.0": { 1547 1054 "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" 1548 1055 }, ··· 1559 1066 "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 1560 1067 "dependencies": [ 1561 1068 "braces", 1562 - "picomatch@2.3.1" 1069 + "picomatch" 1563 1070 ] 1564 1071 }, 1565 1072 "mime-db@1.52.0": { ··· 1575 1082 "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 1576 1083 "bin": true 1577 1084 }, 1578 - "minimatch@9.0.5": { 1579 - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 1580 - "dependencies": [ 1581 - "brace-expansion" 1582 - ] 1583 - }, 1584 1085 "minipass@7.1.2": { 1585 1086 "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==" 1586 1087 }, ··· 1609 1110 "multiformats@9.9.0": { 1610 1111 "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" 1611 1112 }, 1612 - "nanoid@3.3.11": { 1613 - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 1614 - "bin": true 1615 - }, 1616 1113 "negotiator@0.6.3": { 1617 1114 "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 1618 1115 }, ··· 1638 1135 "ee-first" 1639 1136 ] 1640 1137 }, 1641 - "parse-srcset@1.0.2": { 1642 - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" 1643 - }, 1644 1138 "parseurl@1.3.3": { 1645 1139 "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 1646 - }, 1647 - "path-browserify@1.0.1": { 1648 - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" 1649 1140 }, 1650 1141 "path-to-regexp@0.1.12": { 1651 1142 "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" ··· 1655 1146 }, 1656 1147 "picomatch@2.3.1": { 1657 1148 "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" 1658 - }, 1659 - "picomatch@4.0.2": { 1660 - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" 1661 1149 }, 1662 1150 "pino-abstract-transport@1.2.0": { 1663 1151 "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", ··· 1695 1183 "tslib@2.4.0" 1696 1184 ] 1697 1185 }, 1698 - "postcss@8.5.3": { 1699 - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", 1700 - "dependencies": [ 1701 - "nanoid", 1702 - "picocolors", 1703 - "source-map-js" 1704 - ] 1705 - }, 1706 1186 "preact-render-to-string@6.5.13_preact@10.26.6": { 1707 1187 "integrity": "sha512-iGPd+hKPMFKsfpR2vL4kJ6ZPcFIoWZEcBf0Dpm3zOpdVvj77aY8RlLiQji5OMrngEyaxGogeakTb54uS2FvA6w==", 1708 1188 "dependencies": [ ··· 1712 1192 "preact@10.26.6": { 1713 1193 "integrity": "sha512-5SRRBinwpwkaD+OqlBDeITlRgvd8I8QlxHJw9AxSdMNV6O+LodN9nUyYGpSF7sadHjs6RzeFShMexC6DbtWr9g==" 1714 1194 }, 1715 - "prettier@3.5.3": { 1716 - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", 1717 - "bin": true 1718 - }, 1719 - "prismjs@1.30.0": { 1720 - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==" 1721 - }, 1722 1195 "process-warning@3.0.0": { 1723 1196 "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" 1724 1197 }, ··· 1787 1260 "safer-buffer@2.1.2": { 1788 1261 "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1789 1262 }, 1790 - "sanitize-html@2.17.0": { 1791 - "integrity": "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==", 1792 - "dependencies": [ 1793 - "deepmerge", 1794 - "escape-string-regexp", 1795 - "htmlparser2", 1796 - "is-plain-object", 1797 - "parse-srcset", 1798 - "postcss" 1799 - ] 1800 - }, 1801 - "semver@7.7.2": { 1802 - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", 1803 - "bin": true 1804 - }, 1805 1263 "send@0.19.0": { 1806 1264 "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 1807 1265 "dependencies": [ ··· 1832 1290 "setprototypeof@1.2.0": { 1833 1291 "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 1834 1292 }, 1835 - "sharp@0.34.1": { 1836 - "integrity": "sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==", 1837 - "dependencies": [ 1838 - "color", 1839 - "detect-libc@2.0.4", 1840 - "semver" 1841 - ], 1842 - "optionalDependencies": [ 1843 - "@img/sharp-darwin-arm64", 1844 - "@img/sharp-darwin-x64", 1845 - "@img/sharp-libvips-darwin-arm64", 1846 - "@img/sharp-libvips-darwin-x64", 1847 - "@img/sharp-libvips-linux-arm", 1848 - "@img/sharp-libvips-linux-arm64", 1849 - "@img/sharp-libvips-linux-ppc64", 1850 - "@img/sharp-libvips-linux-s390x", 1851 - "@img/sharp-libvips-linux-x64", 1852 - "@img/sharp-libvips-linuxmusl-arm64", 1853 - "@img/sharp-libvips-linuxmusl-x64", 1854 - "@img/sharp-linux-arm", 1855 - "@img/sharp-linux-arm64", 1856 - "@img/sharp-linux-s390x", 1857 - "@img/sharp-linux-x64", 1858 - "@img/sharp-linuxmusl-arm64", 1859 - "@img/sharp-linuxmusl-x64", 1860 - "@img/sharp-wasm32", 1861 - "@img/sharp-win32-ia32", 1862 - "@img/sharp-win32-x64" 1863 - ], 1864 - "scripts": true 1865 - }, 1866 1293 "side-channel-list@1.0.0": { 1867 1294 "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", 1868 1295 "dependencies": [ ··· 1899 1326 "side-channel-weakmap" 1900 1327 ] 1901 1328 }, 1902 - "simple-swizzle@0.2.2": { 1903 - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", 1904 - "dependencies": [ 1905 - "is-arrayish" 1906 - ] 1907 - }, 1908 1329 "sonic-boom@3.8.1": { 1909 1330 "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", 1910 1331 "dependencies": [ ··· 1933 1354 "tslib@2.4.0" 1934 1355 ] 1935 1356 }, 1936 - "supports-color@7.2.0": { 1937 - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1938 - "dependencies": [ 1939 - "has-flag" 1940 - ] 1941 - }, 1942 1357 "tailwind-merge@3.3.0": { 1943 1358 "integrity": "sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==" 1944 1359 }, ··· 1965 1380 "real-require" 1966 1381 ] 1967 1382 }, 1968 - "tinyglobby@0.2.13_picomatch@4.0.2": { 1969 - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", 1970 - "dependencies": [ 1971 - "fdir", 1972 - "picomatch@4.0.2" 1973 - ] 1974 - }, 1975 1383 "tlds@1.259.0": { 1976 1384 "integrity": "sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw==", 1977 1385 "bin": true ··· 1985 1393 "toidentifier@1.0.1": { 1986 1394 "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 1987 1395 }, 1988 - "ts-morph@24.0.0": { 1989 - "integrity": "sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw==", 1990 - "dependencies": [ 1991 - "@ts-morph/common", 1992 - "code-block-writer" 1993 - ] 1994 - }, 1995 1396 "tslib@2.4.0": { 1996 1397 "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" 1997 1398 }, ··· 2019 1420 "dependencies": [ 2020 1421 "multiformats@9.9.0" 2021 1422 ] 2022 - }, 2023 - "undici-types@6.21.0": { 2024 - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" 2025 1423 }, 2026 1424 "undici@6.21.3": { 2027 1425 "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==" ··· 2041 1439 "yallist@5.0.0": { 2042 1440 "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==" 2043 1441 }, 2044 - "yesno@0.4.0": { 2045 - "integrity": "sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==" 2046 - }, 2047 1442 "zod@3.25.7": { 2048 1443 "integrity": "sha512-YGdT1cVRmKkOg6Sq7vY7IkxdphySKnXhaUmFI4r4FcuFVNgpCb9tZfNwXbT6BPjD5oz0nubFsoo9pIqKrDcCvg==" 2049 1444 } 2050 1445 }, 2051 1446 "workspace": { 2052 1447 "dependencies": [ 2053 - "jsr:@bigmoves/bff@0.3.0-beta.25", 1448 + "jsr:@bigmoves/bff@0.3.0-beta.27", 2054 1449 "jsr:@gfx/canvas@~0.5.8", 2055 1450 "jsr:@std/path@^1.0.9", 2056 1451 "npm:@atproto/syntax@0.4",
+1
fly.toml
··· 14 14 BFF_PORT = '8081' 15 15 BFF_PUBLIC_URL = 'https://grain.social' 16 16 GOATCOUNTER_URL = 'https://grain.goatcounter.com/count' 17 + USE_CDN = 'true' 17 18 18 19 [[mounts]] 19 20 source = "litefs"
+39
local-infra/Caddyfile
··· 1 + { 2 + storage file_system /data/ 3 + debug 4 + pki { 5 + ca grain { 6 + name "Grain" 7 + } 8 + } 9 + } 10 + 11 + plc.dev.grain.social { 12 + tls { 13 + issuer internal { 14 + ca grain 15 + } 16 + } 17 + 18 + reverse_proxy http://plc:8080 19 + } 20 + 21 + *.pds.dev.grain.social, pds.dev.grain.social { 22 + tls { 23 + issuer internal { 24 + ca grain 25 + } 26 + } 27 + 28 + reverse_proxy http://pds:3000 29 + } 30 + 31 + jetstream.dev.grain.social { 32 + tls { 33 + issuer internal { 34 + ca grain 35 + } 36 + } 37 + 38 + reverse_proxy http://jetstream:6008 39 + }
+93
local-infra/docker-compose.yml
··· 1 + name: grain_infra 2 + services: 3 + maildev: 4 + image: maildev/maildev 5 + restart: always 6 + environment: 7 + - TZ=America/Los_Angeles 8 + - MAILDEV_WEB_PORT=1080 9 + - MAILDEV_SMTP_PORT=1025 10 + ports: 11 + - "8050:1080" 12 + - "1025:1025" 13 + logging: 14 + driver: "json-file" 15 + options: 16 + max-size: "1m" 17 + 18 + caddy: 19 + container_name: caddy 20 + image: caddy:2 21 + depends_on: 22 + - pds 23 + restart: unless-stopped 24 + cap_add: 25 + - NET_ADMIN 26 + ports: 27 + - "80:80" 28 + - "443:443" 29 + - "443:443/udp" 30 + volumes: 31 + - ./Caddyfile:/etc/caddy/Caddyfile 32 + - caddy_data:/data 33 + - caddy_config:/config 34 + 35 + pds: 36 + image: ghcr.io/bluesky-social/pds:0.4 37 + container_name: pds 38 + restart: unless-stopped 39 + ports: 40 + - '4001:3000' 41 + volumes: 42 + - pds:/pds 43 + env_file: 44 + - ./pds.env 45 + 46 + plc: 47 + image: ghcr.io/bluesky-social/did-method-plc:plc-f2ab7516bac5bc0f3f86842fa94e996bd1b3815b 48 + platform: linux/amd64 49 + container_name: plc 50 + restart: unless-stopped 51 + ports: 52 + - '4000:8080' 53 + depends_on: 54 + - plc_db 55 + environment: 56 + DEBUG_MODE: 1 57 + LOG_ENABLED: "true" 58 + LOG_LEVEL: "debug" 59 + LOG_DESTINATION: 1 60 + DB_CREDS_JSON: &DB_CREDS_JSON '{"username":"pg","password":"password","host":"plc_db","port":5432}' 61 + DB_MIGRATE_CREDS_JSON: *DB_CREDS_JSON 62 + PLC_VERSION: 0.0.1 63 + PORT: 8080 64 + 65 + plc_db: 66 + image: postgres:14.4-alpine 67 + container_name: plc_db 68 + environment: 69 + - POSTGRES_USER=pg 70 + - POSTGRES_PASSWORD=password 71 + ports: 72 + - '5433:5432' 73 + volumes: 74 + - plc:/var/lib/postgresql/data 75 + 76 + jetstream: 77 + container_name: jetstream 78 + image: ghcr.io/bluesky-social/jetstream:sha-0ab10bd 79 + restart: unless-stopped 80 + volumes: 81 + - jetstream:/data 82 + environment: 83 + - JETSTREAM_DATA_DIR=/data 84 + # livness check interval to restart when no events are received (default: 15sec) 85 + - JETSTREAM_LIVENESS_TTL=300s 86 + - JETSTREAM_WS_URL=ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos 87 + 88 + volumes: 89 + caddy_data: 90 + caddy_config: 91 + pds: 92 + plc: 93 + jetstream:
+16
local-infra/pds.env
··· 1 + PDS_JWT_SECRET=8cae8bffcc73d9932819650791e4e89a 2 + PDS_ADMIN_PASSWORD=d6a902588cd93bee1af83f924f60cfd3 3 + PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=2e92e336a50a618458e1097d94a1db86ec3fd8829d7735020cbae80625c761d7 4 + LOG_ENABLED=true 5 + LOG_LEVEL=debug 6 + PDS_BLOBSTORE_DISK_LOCATION=/pds/blocks 7 + PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app 8 + PDS_BSKY_APP_VIEW_URL=https://api.bsky.app 9 + # PDS_CRAWLERS=https://bsky.network 10 + PDS_DATA_DIRECTORY=/pds 11 + PDS_DID_PLC_URL=http://plc:8080 12 + PDS_HOSTNAME=pds.dev.grain.social 13 + PDS_EMAIL_SMTP_URL=smtp://maildev:1025 14 + PDS_EMAIL_FROM_ADDRESS=admin@grain.social 15 + PDS_SERVICE_NAME=Grain Social 16 + PDS_INVITE_REQUIRED=0
+2
src/env.ts
··· 1 1 export const PUBLIC_URL = Deno.env.get("BFF_PUBLIC_URL") ?? 2 2 "http://localhost:8080"; 3 3 export const GOATCOUNTER_URL = Deno.env.get("GOATCOUNTER_URL"); 4 + export const USE_CDN = Deno.env.get("USE_CDN") === "true"; 5 + export const PDS_HOST_URL = Deno.env.get("PDS_HOST_URL");
+3
src/main.tsx
··· 2 2 import { bff, BffContext, JETSTREAM, oauth, route } from "@bigmoves/bff"; 3 3 import { Root } from "./app.tsx"; 4 4 import { LoginPage } from "./components/LoginPage.tsx"; 5 + import { PDS_HOST_URL } from "./env.ts"; 5 6 import { onError } from "./errors.ts"; 6 7 import * as actionHandlers from "./routes/actions.tsx"; 7 8 import * as dialogHandlers from "./routes/dialogs.tsx"; ··· 47 48 oauth({ 48 49 onSignedIn, 49 50 LoginComponent: LoginPage, 51 + createAccountPdsHost: PDS_HOST_URL, 50 52 }), 51 53 route("/", timelineHandler), 52 54 route("/explore", exploreHandler), ··· 94 96 ["POST"], 95 97 actionHandlers.gallerySort, 96 98 ), 99 + route("/actions/get-blob", ["GET"], actionHandlers.getBlob), 97 100 ...photoUploadRoutes(), 98 101 ], 99 102 });
+15 -5
src/photo.ts
··· 2 2 import { PhotoView } from "$lexicon/types/social/grain/photo/defs.ts"; 3 3 import { $Typed } from "$lexicon/util.ts"; 4 4 import { WithBffMeta } from "@bigmoves/bff"; 5 + import { PUBLIC_URL, USE_CDN } from "./env.ts"; 5 6 6 7 export function photoThumb(did: string, cid: string) { 7 - return `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${cid}@jpeg`; 8 + return photoUrl(did, cid, "thumbnail"); 8 9 } 9 10 10 11 export function photoToView( ··· 15 16 $type: "social.grain.photo.defs#photoView", 16 17 uri: photo.uri, 17 18 cid: photo.photo.ref.toString(), 18 - thumb: 19 - `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${photo.photo.ref.toString()}@jpeg`, 20 - fullsize: 21 - `https://cdn.bsky.app/img/feed_fullsize/plain/${did}/${photo.photo.ref.toString()}@jpeg`, 19 + thumb: photoUrl(did, photo.photo.ref.toString(), "thumbnail"), 20 + fullsize: photoUrl(did, photo.photo.ref.toString(), "fullsize"), 22 21 alt: photo.alt, 23 22 aspectRatio: photo.aspectRatio, 24 23 }; 25 24 } 25 + 26 + export function photoUrl( 27 + did: string, 28 + cid: string, 29 + type: "thumbnail" | "fullsize" = "fullsize", 30 + ): string { 31 + if (!USE_CDN) { 32 + return `${PUBLIC_URL}/actions/get-blob?did=${did}&cid=${cid}`; 33 + } 34 + return `https://cdn.bsky.app/img/feed_${type}/plain/${did}/${cid}@jpeg`; 35 + }
+42
src/routes/actions.tsx
··· 386 386 387 387 return ctx.redirect(`/profile/${handle}`); 388 388 }; 389 + 390 + export const getBlob: RouteHandler = async ( 391 + req, 392 + _params, 393 + ctx: BffContext<State>, 394 + ) => { 395 + const url = new URL(req.url); 396 + const did = url.searchParams.get("did"); 397 + const cid = url.searchParams.get("cid"); 398 + if (!did || !cid) { 399 + return new Response("Missing did or cid", { status: 400 }); 400 + } 401 + 402 + const atpData = await ctx.didResolver.resolveAtprotoData(did); 403 + if (!atpData) { 404 + return new Response("ATP not found", { status: 404 }); 405 + } 406 + 407 + const blobUrl = 408 + `${atpData.pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`; 409 + 410 + try { 411 + const response = await fetch(blobUrl); 412 + if (!response.ok) { 413 + return new Response(`Failed to fetch blob: ${response.statusText}`, { 414 + status: response.status, 415 + }); 416 + } 417 + 418 + const blobData = await response.arrayBuffer(); 419 + return new Response(blobData, { 420 + status: 200, 421 + headers: { 422 + "Content-Type": "image/jpeg", 423 + "Cache-Control": "max-age=31536000, public", 424 + }, 425 + }); 426 + } catch (error) { 427 + console.error("Error fetching blob:", error); 428 + return new Response("Error fetching blob", { status: 500 }); 429 + } 430 + };