[READ-ONLY] Mirror of https://github.com/bombshell-dev/rfd.
0

Configure Feed

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

move server into www

Nate Moore (May 10, 2026, 12:27 AM EDT) e1e3e195 4fa32738

+764 -92
-27
packages/server/package.json
··· 1 - { 2 - "name": "server", 3 - "type": "module", 4 - "version": "0.0.1", 5 - "private": true, 6 - "main": "./src/index.ts", 7 - "scripts": { 8 - "dev": "wrangler dev", 9 - "deploy": "wrangler deploy", 10 - "test": "vitest run", 11 - "test:watch": "vitest" 12 - }, 13 - "dependencies": { 14 - "@atcute/atproto": "^4.0.0", 15 - "@atcute/client": "^2.0.0", 16 - "@atcute/identity": "^2.0.0", 17 - "@atcute/identity-resolver": "^2.0.0", 18 - "@atcute/lexicons": "^2.0.0", 19 - "hono": "^4.0.0", 20 - "lexicon": "workspace:*" 21 - }, 22 - "devDependencies": { 23 - "@cloudflare/workers-types": "^4.0.0", 24 - "vitest": "^4.0.0", 25 - "wrangler": "^4.0.0" 26 - } 27 - }
packages/server/src/atproto.ts packages/www/src/lib/atproto.ts
-22
packages/server/src/index.ts
··· 1 - import type {} from '@atcute/atproto'; 2 - import { Hono } from 'hono'; 3 - import type { ActorIdentifier } from '@atcute/lexicons/syntax'; 4 - 5 - import { fetchPull } from './pull.ts'; 6 - 7 - const app = new Hono(); 8 - 9 - app.get('/healthz', (c) => c.json({ ok: true })); 10 - 11 - app.get('/:handle/:repo/pulls/:rkey', async (c) => { 12 - const { handle, repo, rkey } = c.req.param(); 13 - const result = await fetchPull({ handle: handle as ActorIdentifier, repo, rkey }); 14 - return c.json(result); 15 - }); 16 - 17 - app.onError((err, c) => { 18 - console.error(err); 19 - return c.json({ error: err.message ?? String(err) }, 500); 20 - }); 21 - 22 - export default app;
packages/server/src/patch.ts packages/www/src/lib/patch.ts
+3 -3
packages/server/src/pull.ts packages/www/src/lib/pull.ts
··· 1 1 import { parseCanonicalResourceUri } from '@atcute/lexicons/syntax'; 2 2 import type { ActorIdentifier, Did, ResourceUri } from '@atcute/lexicons/syntax'; 3 - import type * as Pull from 'lexicon/types/repo/pull'; 4 - import type * as PullComment from 'lexicon/types/repo/pull/comment'; 5 - import type * as Repo from 'lexicon/types/repo'; 3 + import type * as Pull from 'lexicon/types/sh/tangled/repo/pull'; 4 + import type * as PullComment from 'lexicon/types/sh/tangled/repo/pull/comment'; 5 + import type * as Repo from 'lexicon/types/sh/tangled/repo'; 6 6 7 7 import { clientFor, resolveActor } from './atproto.ts'; 8 8 import { extractMarkdownFromPatch, type ExtractedMarkdown } from './patch.ts';
+1 -1
packages/server/test/patch.test.ts packages/www/test/patch.test.ts
··· 1 1 import { describe, expect, it } from 'vitest'; 2 2 3 - import { extractMarkdownFromDiff, gunzipToString } from '../src/patch.ts'; 3 + import { extractMarkdownFromDiff, gunzipToString } from '../src/lib/patch.ts'; 4 4 5 5 const ADD_MD_PATCH = `From abc123 Mon Sep 17 00:00:00 2001 6 6 From: Jane Doe <jane@example.com>
-14
packages/server/tsconfig.json
··· 1 - { 2 - "extends": "../../tsconfig.json", 3 - "compilerOptions": { 4 - "types": ["@cloudflare/workers-types", "@atcute/atproto"], 5 - "moduleResolution": "bundler", 6 - "module": "esnext", 7 - "lib": ["es2022"], 8 - "noEmit": true, 9 - "composite": false, 10 - "declaration": false, 11 - "declarationMap": false 12 - }, 13 - "include": ["src/**/*", "test/**/*"] 14 - }
-3
packages/server/wrangler.toml
··· 1 - name = "rfd-server" 2 - main = "src/index.ts" 3 - compatibility_date = "2026-05-01"
-5
packages/www/astro.config.mjs
··· 1 - // @ts-check 2 - import { defineConfig } from 'astro/config'; 3 - 4 - // https://astro.build/config 5 - export default defineConfig({});
+12
packages/www/astro.config.ts
··· 1 + import { defineConfig } from 'astro/config'; 2 + import cloudflare from '@astrojs/cloudflare'; 3 + 4 + // https://astro.build/config 5 + export default defineConfig({ 6 + output: 'server', 7 + adapter: cloudflare(), 8 + experimental: { 9 + rustCompiler: true, 10 + advancedRouting: true 11 + } 12 + });
+24 -4
packages/www/package.json
··· 6 6 "node": ">=24.15.0" 7 7 }, 8 8 "scripts": { 9 - "dev": "astro dev", 9 + "dev": "astro dev --host 127.0.0.1 --port 4321", 10 10 "build": "astro build", 11 - "preview": "astro preview", 12 - "astro": "astro" 11 + "preview": "wrangler dev", 12 + "astro": "astro", 13 + "test": "vitest run", 14 + "generate-types": "wrangler types" 13 15 }, 14 16 "dependencies": { 15 - "astro": "^6.3.1" 17 + "@astrojs/cloudflare": "^13.5.0", 18 + "@atcute/atproto": "^4.0.0", 19 + "@atcute/client": "^2.0.0", 20 + "@atcute/identity": "^2.0.0", 21 + "@atcute/identity-resolver": "^2.0.0", 22 + "@atcute/lexicons": "^2.0.0", 23 + "@atcute/oauth-browser-client": "^4.0.0", 24 + "astro": "^6.3.1", 25 + "hono": "^4.0.0", 26 + "lexicon": "workspace:*", 27 + "wrangler": "^4.90.0" 28 + }, 29 + "devDependencies": { 30 + "@astrojs/compiler-rs": "^0.1.10", 31 + "@cloudflare/workers-types": "^4.0.0", 32 + "vitest": "^4.0.0" 33 + }, 34 + "overrides": { 35 + "vite": "^7" 16 36 } 17 37 }
+13
packages/www/src/api/discussion.ts
··· 1 + import type { ActorIdentifier } from '@atcute/lexicons/syntax'; 2 + import { Hono } from 'hono'; 3 + 4 + import { getDiscussionRepo } from '../lib/discussion.ts'; 5 + 6 + const app = new Hono(); 7 + 8 + app.get('/:handle', async (c) => { 9 + const { handle } = c.req.param(); 10 + return c.json(await getDiscussionRepo(handle as ActorIdentifier)); 11 + }); 12 + 13 + export default app;
+7
packages/www/src/api/healthz.ts
··· 1 + import { Hono } from 'hono'; 2 + 3 + const app = new Hono(); 4 + 5 + app.get('/', (c) => c.json({ ok: true })); 6 + 7 + export default app;
+13
packages/www/src/api/pulls.ts
··· 1 + import type { ActorIdentifier } from '@atcute/lexicons/syntax'; 2 + import { Hono } from 'hono'; 3 + 4 + import { fetchPull } from '../lib/pull.ts'; 5 + 6 + const app = new Hono(); 7 + 8 + app.get('/:handle/:repo/pulls/:rkey', async (c) => { 9 + const { handle, repo, rkey } = c.req.param(); 10 + return c.json(await fetchPull({ handle: handle as ActorIdentifier, repo, rkey })); 11 + }); 12 + 13 + export default app;
+25
packages/www/src/app.ts
··· 1 + import { pages } from 'astro/hono'; 2 + import { Hono } from 'hono'; 3 + 4 + import discussion from './api/discussion.ts'; 5 + import healthz from './api/healthz.ts'; 6 + import pulls from './api/pulls.ts'; 7 + import { NoDiscussionRepoError } from './lib/discussion.ts'; 8 + 9 + const api = new Hono(); 10 + api.route('/healthz', healthz); 11 + api.route('/', discussion); 12 + api.route('/', pulls); 13 + api.onError((err, c) => { 14 + console.error(err); 15 + if (err instanceof NoDiscussionRepoError) { 16 + return c.json({ error: err.message }, 404); 17 + } 18 + return c.json({ error: err.message ?? String(err) }, 500); 19 + }); 20 + 21 + const app = new Hono(); 22 + app.route('/api/v0', api); 23 + app.use(pages()); 24 + 25 + export default app;
+80
packages/www/src/lib/discussion.ts
··· 1 + import { parseCanonicalResourceUri } from '@atcute/lexicons/syntax'; 2 + import type { ActorIdentifier, Did } from '@atcute/lexicons/syntax'; 3 + import type * as DiscussionRepo from 'lexicon/types/st/itch/discussion/repo'; 4 + import type * as Repo from 'lexicon/types/sh/tangled/repo'; 5 + 6 + import { clientFor, resolveActor } from './atproto.ts'; 7 + 8 + export interface DiscussionRepoView { 9 + claim: { 10 + uri: string; 11 + cid: string; 12 + repo: string; 13 + createdAt: string; 14 + }; 15 + repo: { 16 + uri: string; 17 + cid: string; 18 + name: string; 19 + knot: string; 20 + description?: string; 21 + createdAt: string; 22 + owner: { did: string; handle?: string }; 23 + }; 24 + } 25 + 26 + export class NoDiscussionRepoError extends Error { 27 + override name = 'NoDiscussionRepoError'; 28 + constructor(handle: string) { 29 + super(`no discussion repo claimed for ${handle}`); 30 + } 31 + } 32 + 33 + export async function getDiscussionRepo(handle: ActorIdentifier): Promise<DiscussionRepoView> { 34 + const claimer = await resolveActor(handle); 35 + const claimerRpc = clientFor(claimer.pds); 36 + 37 + let claimRes; 38 + try { 39 + claimRes = await claimerRpc.get('com.atproto.repo.getRecord', { 40 + params: { 41 + repo: claimer.did as Did, 42 + collection: 'st.itch.discussion.repo', 43 + rkey: 'self', 44 + }, 45 + }); 46 + } catch (err) { 47 + throw new NoDiscussionRepoError(claimer.handle); 48 + } 49 + const claimValue = claimRes.data.value as DiscussionRepo.Main; 50 + 51 + const parsed = parseCanonicalResourceUri(claimValue.repo); 52 + const owner = await resolveActor(parsed.repo as ActorIdentifier); 53 + const ownerRpc = clientFor(owner.pds); 54 + const repoRes = await ownerRpc.get('com.atproto.repo.getRecord', { 55 + params: { 56 + repo: parsed.repo, 57 + collection: 'sh.tangled.repo', 58 + rkey: parsed.rkey, 59 + }, 60 + }); 61 + const repoValue = repoRes.data.value as Repo.Main; 62 + 63 + return { 64 + claim: { 65 + uri: claimRes.data.uri, 66 + cid: claimRes.data.cid ?? '', 67 + repo: claimValue.repo, 68 + createdAt: claimValue.createdAt, 69 + }, 70 + repo: { 71 + uri: repoRes.data.uri, 72 + cid: repoRes.data.cid ?? '', 73 + name: repoValue.name, 74 + knot: repoValue.knot, 75 + description: repoValue.description, 76 + createdAt: repoValue.createdAt, 77 + owner: { did: owner.did, handle: owner.handle }, 78 + }, 79 + }; 80 + }
+110
packages/www/src/lib/oauth.ts
··· 1 + import { XRPC } from '@atcute/client'; 2 + import { 3 + CompositeDidDocumentResolver, 4 + CompositeHandleResolver, 5 + DohJsonHandleResolver, 6 + LocalActorResolver, 7 + PlcDidDocumentResolver, 8 + WebDidDocumentResolver, 9 + WellKnownHandleResolver, 10 + } from '@atcute/identity-resolver'; 11 + import { 12 + configureOAuth, 13 + createAuthorizationUrl, 14 + deleteStoredSession, 15 + finalizeAuthorization, 16 + getSession, 17 + OAuthUserAgent, 18 + type Session, 19 + } from '@atcute/oauth-browser-client'; 20 + 21 + let configured = false; 22 + 23 + export const SCOPE = 'atproto transition:generic'; 24 + 25 + /** 26 + * Build the OAuth `client_id` for the current origin. 27 + * 28 + * - **Dev (loopback)**: atproto OAuth's loopback exception requires 29 + * `http://localhost?redirect_uri=<encoded>&scope=<encoded>`. The redirect 30 + * itself uses 127.0.0.1 (loopback IP); only the client_id authority is the 31 + * literal `localhost`. The auth server doesn't fetch this URL — it parses 32 + * the params directly. 33 + * - **Prod**: a regular https URL pointing at the hosted client metadata JSON. 34 + */ 35 + function clientIdFor(origin: string, redirectUri: string): string { 36 + const url = new URL(origin); 37 + const isLoopback = url.hostname === '127.0.0.1' || url.hostname === 'localhost'; 38 + if (isLoopback) { 39 + const params = new URLSearchParams({ redirect_uri: redirectUri, scope: SCOPE }); 40 + return `http://localhost?${params.toString()}`; 41 + } 42 + return `${origin}/oauth/client-metadata.json`; 43 + } 44 + 45 + export function configure(origin: string = location.origin): void { 46 + if (configured) return; 47 + const handleResolver = new CompositeHandleResolver({ 48 + strategy: 'race', 49 + methods: { 50 + dns: new DohJsonHandleResolver({ dohUrl: 'https://mozilla.cloudflare-dns.com/dns-query' }), 51 + http: new WellKnownHandleResolver(), 52 + }, 53 + }); 54 + const didDocumentResolver = new CompositeDidDocumentResolver({ 55 + methods: { 56 + plc: new PlcDidDocumentResolver(), 57 + web: new WebDidDocumentResolver(), 58 + }, 59 + }); 60 + const redirectUri = `${origin}/oauth/callback`; 61 + configureOAuth({ 62 + metadata: { 63 + client_id: clientIdFor(origin, redirectUri), 64 + redirect_uri: redirectUri, 65 + }, 66 + identityResolver: new LocalActorResolver({ handleResolver, didDocumentResolver }), 67 + }); 68 + configured = true; 69 + } 70 + 71 + export async function startLogin(handle: string): Promise<void> { 72 + const url = await createAuthorizationUrl({ 73 + target: { type: 'account', identifier: handle as never }, 74 + scope: SCOPE, 75 + }); 76 + location.assign(url); 77 + } 78 + 79 + export async function finishLogin(): Promise<Session> { 80 + // atproto OAuth servers may return the response in either the URL fragment 81 + // (default for browser public clients) or the query string. Try both. 82 + const hash = new URLSearchParams(location.hash.slice(1)); 83 + const search = new URLSearchParams(location.search); 84 + const params = hash.has('state') || hash.has('error') ? hash : search; 85 + const { session } = await finalizeAuthorization(params); 86 + return session; 87 + } 88 + 89 + export function agentForSession(session: Session): { 90 + agent: OAuthUserAgent; 91 + rpc: XRPC; 92 + } { 93 + const agent = new OAuthUserAgent(session); 94 + const rpc = new XRPC({ handler: agent }); 95 + return { agent, rpc }; 96 + } 97 + 98 + export async function resumeAgent(did: string): Promise<{ agent: OAuthUserAgent; rpc: XRPC }> { 99 + const session = await getSession(did as never, { allowStale: true }); 100 + return agentForSession(session); 101 + } 102 + 103 + export async function signOut(did: string): Promise<void> { 104 + try { 105 + const { agent } = await resumeAgent(did); 106 + await agent.signOut(); 107 + } catch { 108 + await deleteStoredSession(did as never); 109 + } 110 + }
+104
packages/www/src/pages/claim.astro
··· 1 + --- 2 + --- 3 + <!doctype html> 4 + <html lang="en"> 5 + <head> 6 + <meta charset="utf-8" /> 7 + <title>Pick your discussion repo — st.itch</title> 8 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 9 + </head> 10 + <body> 11 + <main> 12 + <h1>Pick your discussion repo</h1> 13 + <p id="status">Loading your tangled repos…</p> 14 + <p id="error" role="alert" hidden></p> 15 + <ul id="repos" hidden></ul> 16 + <p id="empty" hidden> 17 + You have no <code>sh.tangled.repo</code> records yet. Create one on 18 + <a href="https://tangled.org">tangled.org</a> first. 19 + </p> 20 + <p id="success" hidden> 21 + Claimed! Verify at <a id="verify-link" href="#" target="_blank" rel="noopener"></a> 22 + </p> 23 + </main> 24 + <script> 25 + import { configure, resumeAgent } from '../lib/oauth.ts'; 26 + 27 + const status = document.getElementById('status'); 28 + const error = document.getElementById('error'); 29 + const list = document.getElementById('repos'); 30 + const empty = document.getElementById('empty'); 31 + const success = document.getElementById('success'); 32 + const verifyLink = document.getElementById('verify-link'); 33 + 34 + const showError = (msg) => { 35 + status.hidden = true; 36 + error.textContent = msg; 37 + error.hidden = false; 38 + }; 39 + 40 + const did = sessionStorage.getItem('rfd:did'); 41 + if (!did) { 42 + location.replace('/login'); 43 + } else { 44 + try { 45 + configure(); 46 + const { rpc } = await resumeAgent(did); 47 + 48 + const repos = await rpc.get('com.atproto.repo.listRecords', { 49 + params: { repo: did, collection: 'sh.tangled.repo', limit: 100 }, 50 + }); 51 + 52 + status.hidden = true; 53 + if (repos.data.records.length === 0) { 54 + empty.hidden = false; 55 + } else { 56 + list.hidden = false; 57 + for (const record of repos.data.records) { 58 + const li = document.createElement('li'); 59 + const button = document.createElement('button'); 60 + button.type = 'button'; 61 + const value = record.value; 62 + button.textContent = `${value.name} · ${value.knot}${value.description ? ' — ' + value.description : ''}`; 63 + button.addEventListener('click', async () => { 64 + button.disabled = true; 65 + try { 66 + await rpc.call('com.atproto.repo.putRecord', { 67 + data: { 68 + repo: did, 69 + collection: 'st.itch.discussion.repo', 70 + rkey: 'self', 71 + record: { 72 + $type: 'st.itch.discussion.repo', 73 + repo: record.uri, 74 + createdAt: new Date().toISOString(), 75 + }, 76 + }, 77 + }); 78 + list.hidden = true; 79 + success.hidden = false; 80 + // Best-effort handle resolution for the verify link; 81 + // fall back to DID if we can't infer it from the response. 82 + const handle = await rpc 83 + .get('com.atproto.repo.describeRepo', { params: { repo: did } }) 84 + .then((r) => r.data.handle ?? did) 85 + .catch(() => did); 86 + const apiUrl = `/api/v0/${handle}`; 87 + verifyLink.href = apiUrl; 88 + verifyLink.textContent = apiUrl; 89 + } catch (err) { 90 + button.disabled = false; 91 + showError(err?.message ?? String(err)); 92 + } 93 + }); 94 + li.appendChild(button); 95 + list.appendChild(li); 96 + } 97 + } 98 + } catch (err) { 99 + showError(err?.message ?? String(err)); 100 + } 101 + } 102 + </script> 103 + </body> 104 + </html>
+41
packages/www/src/pages/login.astro
··· 1 + --- 2 + --- 3 + <!doctype html> 4 + <html lang="en"> 5 + <head> 6 + <meta charset="utf-8" /> 7 + <title>Sign in — st.itch</title> 8 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 9 + </head> 10 + <body> 11 + <main> 12 + <h1>Sign in</h1> 13 + <form id="login-form"> 14 + <label> 15 + Handle 16 + <input type="text" name="handle" placeholder="alice.bsky.social" required autofocus /> 17 + </label> 18 + <button type="submit">Continue</button> 19 + </form> 20 + <p id="error" role="alert" hidden></p> 21 + </main> 22 + <script> 23 + import { configure, startLogin } from '../lib/oauth.ts'; 24 + configure(); 25 + const form = document.getElementById('login-form'); 26 + const error = document.getElementById('error'); 27 + form.addEventListener('submit', async (e) => { 28 + e.preventDefault(); 29 + error.hidden = true; 30 + const handle = new FormData(form).get('handle')?.toString().trim(); 31 + if (!handle) return; 32 + try { 33 + await startLogin(handle); 34 + } catch (err) { 35 + error.textContent = err?.message ?? String(err); 36 + error.hidden = false; 37 + } 38 + }); 39 + </script> 40 + </body> 41 + </html>
+31
packages/www/src/pages/oauth/callback.astro
··· 1 + --- 2 + --- 3 + <!doctype html> 4 + <html lang="en"> 5 + <head> 6 + <meta charset="utf-8" /> 7 + <title>Signing in… — st.itch</title> 8 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 9 + </head> 10 + <body> 11 + <main> 12 + <p id="status">Finishing sign-in…</p> 13 + <p id="error" role="alert" hidden></p> 14 + </main> 15 + <script> 16 + import { configure, finishLogin } from '../../lib/oauth.ts'; 17 + const status = document.getElementById('status'); 18 + const error = document.getElementById('error'); 19 + try { 20 + configure(); 21 + const session = await finishLogin(); 22 + sessionStorage.setItem('rfd:did', session.info.sub); 23 + location.replace('/claim'); 24 + } catch (err) { 25 + status.hidden = true; 26 + error.textContent = `Sign-in failed: ${err?.message ?? String(err)}`; 27 + error.hidden = false; 28 + } 29 + </script> 30 + </body> 31 + </html>
+22
packages/www/src/pages/oauth/client-metadata.json.ts
··· 1 + import type { APIRoute } from 'astro'; 2 + 3 + export const prerender = false; 4 + 5 + export const GET: APIRoute = ({ url }) => { 6 + const origin = url.origin; 7 + const metadata = { 8 + client_id: `${origin}/oauth/client-metadata.json`, 9 + client_name: 'st.itch RFD', 10 + client_uri: origin, 11 + redirect_uris: [`${origin}/oauth/callback`], 12 + scope: 'atproto transition:generic', 13 + grant_types: ['authorization_code', 'refresh_token'], 14 + response_types: ['code'], 15 + token_endpoint_auth_method: 'none', 16 + application_type: 'web', 17 + dpop_bound_access_tokens: true, 18 + }; 19 + return new Response(JSON.stringify(metadata, null, 2), { 20 + headers: { 'content-type': 'application/json' }, 21 + }); 22 + };
+9 -3
packages/www/tsconfig.json
··· 1 1 { 2 2 "extends": "astro/tsconfigs/strict", 3 - "include": [".astro/types.d.ts", "**/*"], 4 - "exclude": ["dist"] 5 - } 3 + "include": [ 4 + ".astro/types.d.ts", 5 + "**/*", 6 + "./worker-configuration.d.ts" 7 + ], 8 + "exclude": [ 9 + "dist" 10 + ] 11 + }
+13
packages/www/wrangler.jsonc
··· 1 + { 2 + "compatibility_date": "2026-05-10", 3 + "compatibility_flags": ["global_fetch_strictly_public"], 4 + "name": "www", 5 + "main": "@astrojs/cloudflare/entrypoints/server", 6 + "assets": { 7 + "directory": "./dist", 8 + "binding": "ASSETS" 9 + }, 10 + "observability": { 11 + "enabled": true 12 + } 13 + }
+256 -10
pnpm-lock.yaml
··· 19 19 specifier: ^3.0.0 20 20 version: 3.0.0(@atcute/cbor@2.3.3(@atcute/cid@2.4.1))(@atcute/cid@2.4.1) 21 21 22 - packages/server: 22 + packages/www: 23 23 dependencies: 24 + '@astrojs/cloudflare': 25 + specifier: ^13.5.0 26 + version: 13.5.0(astro@6.3.1(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.3)(yaml@2.8.4))(jiti@2.7.0)(lightningcss@1.32.0)(workerd@1.20260507.1)(wrangler@4.90.0(@cloudflare/workers-types@4.20260509.1))(yaml@2.8.4) 24 27 '@atcute/atproto': 25 28 specifier: ^4.0.0 26 29 version: 4.0.0(@atcute/lexicons@2.0.0) ··· 36 39 '@atcute/lexicons': 37 40 specifier: ^2.0.0 38 41 version: 2.0.0 42 + '@atcute/oauth-browser-client': 43 + specifier: ^4.0.0 44 + version: 4.0.0(@atcute/identity-resolver@2.0.0(@atcute/identity@2.0.0(@atcute/lexicons@2.0.0))(@atcute/lexicons@2.0.0))(@atcute/lexicons@2.0.0) 45 + astro: 46 + specifier: ^6.3.1 47 + version: 6.3.1(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.3)(yaml@2.8.4) 39 48 hono: 40 49 specifier: ^4.0.0 41 50 version: 4.12.18 42 51 lexicon: 43 52 specifier: workspace:* 44 53 version: link:../lexicon 54 + wrangler: 55 + specifier: ^4.90.0 56 + version: 4.90.0(@cloudflare/workers-types@4.20260509.1) 45 57 devDependencies: 58 + '@astrojs/compiler-rs': 59 + specifier: ^0.1.10 60 + version: 0.1.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) 46 61 '@cloudflare/workers-types': 47 62 specifier: ^4.0.0 48 63 version: 4.20260509.1 49 64 vitest: 50 65 specifier: ^4.0.0 51 66 version: 4.1.5(vite@8.0.11(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.8.4)) 52 - wrangler: 53 - specifier: ^4.0.0 54 - version: 4.90.0(@cloudflare/workers-types@4.20260509.1) 67 + 68 + packages: 69 + 70 + '@astrojs/cloudflare@13.5.0': 71 + resolution: {integrity: sha512-kP3/SwPzZi7tq+fZG6H9GpaYQF3jw9L6vg92QL6q7FLI7t0rGiuG6Q0AckeJYjBUsO4Y+2w7aI7m+Q2r/WpssQ==} 72 + peerDependencies: 73 + astro: ^6.3.0 74 + wrangler: ^4.83.0 75 + 76 + '@astrojs/compiler-binding-darwin-arm64@0.1.10': 77 + resolution: {integrity: sha512-zDYwHvXVCm91XUm5xBRPbZK6yx9foM+Ut2qHiL0L37r1daF1bGLhnYjNV/VP35OLH5o/A1j+9uvl1xEX2a3ftw==} 78 + engines: {node: ^20.19.0 || >=22.12.0} 79 + cpu: [arm64] 80 + os: [darwin] 81 + 82 + '@astrojs/compiler-binding-darwin-x64@0.1.10': 83 + resolution: {integrity: sha512-EqugPJFuQdG11sG6TtO8uq0njcEyv9y/5gdpBRZJE6aSoM3yWFmTQ/aNU8PWIiz1upZFjdNQ/UUnVNzYd7N7Uw==} 84 + engines: {node: ^20.19.0 || >=22.12.0} 85 + cpu: [x64] 86 + os: [darwin] 87 + 88 + '@astrojs/compiler-binding-linux-arm64-gnu@0.1.10': 89 + resolution: {integrity: sha512-h1UN8yx2vO/0uwnExN/8MNfsDr7OFADVM3Vv0JWeSpmUO6sFOvTsGVAeBBl29up6c4sdT3QJ5rf6sczQsc25dA==} 90 + engines: {node: ^20.19.0 || >=22.12.0} 91 + cpu: [arm64] 92 + os: [linux] 93 + 94 + '@astrojs/compiler-binding-linux-arm64-musl@0.1.10': 95 + resolution: {integrity: sha512-ot1Lksml0FqrrlYa89wGXQM+n290ncj65PZAq8siEWmXsmwoNCYCbqRSwRO6I/cT+PDlmmV0AcFTrp1DEO3PUA==} 96 + engines: {node: ^20.19.0 || >=22.12.0} 97 + cpu: [arm64] 98 + os: [linux] 99 + 100 + '@astrojs/compiler-binding-linux-x64-gnu@0.1.10': 101 + resolution: {integrity: sha512-RGKGCbCvDat+DppnQbiWIhif6ptvkyXMdqOa7NjES4UoqIIUjE3YZfRn8gp3bXUe4ReWv4hGO1TQd2eitONt1g==} 102 + engines: {node: ^20.19.0 || >=22.12.0} 103 + cpu: [x64] 104 + os: [linux] 105 + 106 + '@astrojs/compiler-binding-linux-x64-musl@0.1.10': 107 + resolution: {integrity: sha512-UemMv5Xq9c7trG9Cel4MHAo2wYiCxZ6qIKUnI4NJqBXDtOBqAjcMoqMbw78KYkb9vg2OIewVaJ+YvQrFZs5VBg==} 108 + engines: {node: ^20.19.0 || >=22.12.0} 109 + cpu: [x64] 110 + os: [linux] 55 111 56 - packages/www: 57 - dependencies: 58 - astro: 59 - specifier: ^6.3.1 60 - version: 6.3.1(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.3)(yaml@2.8.4) 112 + '@astrojs/compiler-binding-wasm32-wasi@0.1.10': 113 + resolution: {integrity: sha512-SwawjgiYnm7s5neVKRoHIsnGG06vhuFhKg0iMBO6EsnL19xVbUp61V50gVtdgFlsfXalfH6SHuv2wQw8FhFSNg==} 114 + engines: {node: '>=14.0.0'} 115 + cpu: [wasm32] 61 116 62 - packages: 117 + '@astrojs/compiler-binding-win32-arm64-msvc@0.1.10': 118 + resolution: {integrity: sha512-DKGOtbS8AZztvKUUdzvf+bOp7QLudmQiMHSYobSZKFanryQH5SllOMrZsL2pbDAcfBBrf0WsYWp9R+/ga7gGhQ==} 119 + engines: {node: ^20.19.0 || >=22.12.0} 120 + cpu: [arm64] 121 + os: [win32] 122 + 123 + '@astrojs/compiler-binding-win32-x64-msvc@0.1.10': 124 + resolution: {integrity: sha512-de9Y0GPm19G6SPgUk86ycZNuWEw7AA7vLZvsi/+cNR7tr/vOabU931O22L4bjjS138PFWmBz+qYOH9CT6h6BDA==} 125 + engines: {node: ^20.19.0 || >=22.12.0} 126 + cpu: [x64] 127 + os: [win32] 128 + 129 + '@astrojs/compiler-binding@0.1.10': 130 + resolution: {integrity: sha512-XvsWOM1JTjTDETD4qK2rIIHyPSMtBP+t7+Hmgk1kd4/iiUxLPnyLjnwLKX7N5t1MBHNmGiEA39DOslSMtlnfeg==} 131 + engines: {node: ^20.19.0 || >=22.12.0} 132 + 133 + '@astrojs/compiler-rs@0.1.10': 134 + resolution: {integrity: sha512-Mul2veNSpEzwd1Zk6coIAu9TKyk6RjBJMWaOOrelBBA+ZmcGXhj7MabjowNTOMgvRUU8YHXAHadzoKD0y49uxw==} 63 135 64 136 '@astrojs/compiler@4.0.0': 65 137 resolution: {integrity: sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA==} ··· 77 149 '@astrojs/telemetry@3.3.2': 78 150 resolution: {integrity: sha512-j8DNruA8ors99Al39RYZPJK4DC1bKkoNm93mAMuBhY9TCNC4R8n1q7ovFnJ5qhGh5Lsh7pa1gpQVpYpsJPeTHQ==} 79 151 engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} 152 + 153 + '@astrojs/underscore-redirects@1.0.3': 154 + resolution: {integrity: sha512-cxnGSw+sJigBLdX4TMSZKkzV6C3gMLJMucDk2W+n281Xhie68T2/9f1+1NMNDCZsc5i0FED7Qt5I10g2O9wtZg==} 80 155 81 156 '@atcute/atproto@4.0.0': 82 157 resolution: {integrity: sha512-Rd21kW0tl/QEXhyPkJXRpUV8HYs7sMOmmXRu2z1sKMZbm1tqvHz1L3CQeTFcC/Xf/5cg7S6ITGIKRP0++zu0aw==} ··· 100 175 '@atcute/client@2.0.9': 101 176 resolution: {integrity: sha512-QNDm9gMP6x9LY77ArwY+urQOBtQW74/onEAz42c40JxRm6Rl9K9cU4ROvNKJ+5cpVmEm1sthEWVRmDr5CSZENA==} 102 177 178 + '@atcute/client@5.0.0': 179 + resolution: {integrity: sha512-Dtrc1no1oAtpUTmkBxH0xKSgy8qcnk8orPf/PkEATW+MB3k8FPHtPH2fshiKd55rioZkb+xaN+7A29WtqPQHRA==} 180 + peerDependencies: 181 + '@atcute/lexicons': ^2.0.0 182 + 103 183 '@atcute/crypto@2.4.1': 104 184 resolution: {integrity: sha512-tJ3Pi/XYcAsABKtqSlSOTKfO5YiQ4XdqlTuPS8HiRZSezOPcXBFFzAFWpSIJPURbVPFQL3LLrrK0Ea24wl5qeQ==} 105 185 ··· 143 223 '@atcute/multibase@1.2.0': 144 224 resolution: {integrity: sha512-ZK2GRra+qIYq9nNuQB52m2ul0hOmCQEtPobGfTSUxm7pF0OGEkWGkWHugFhNEDVzHzTwPxHp6VGotdZFue4lYQ==} 145 225 226 + '@atcute/oauth-browser-client@4.0.0': 227 + resolution: {integrity: sha512-rvxmRcA6WOZz5TfcKp1kVtxUioogMzQH5OdCrW3Fm+ldEPPe2ZEyP7x1PzRWo6Es3F8lm4Q7BCJJgJFkQp2a5Q==} 228 + peerDependencies: 229 + '@atcute/identity-resolver': ^2.0.0 230 + '@atcute/lexicons': ^2.0.0 231 + 232 + '@atcute/oauth-crypto@1.0.0': 233 + resolution: {integrity: sha512-2UC1msk4PyUArk/5Pl8zgtz1T8O+LZdFfB8ENLHjQVYitpqzGj2ZpDJaWZvCF3Y8lly4KoeUHLpFPDzbP+3u+g==} 234 + 235 + '@atcute/oauth-keyset@0.1.1': 236 + resolution: {integrity: sha512-BpaaXSuMawxILhWTOR0YIpKzFSA0MQC1W5Hn0HGE+giTqYFAKcdf0oA+2RZG9ZLVIzfO2txBsTeMpxB5qL6lEQ==} 237 + 238 + '@atcute/oauth-types@1.0.0': 239 + resolution: {integrity: sha512-YOpjLU8H5PG6oKfgau+dx7rSmGsLxIA36MeGL7BDeopcyq80RqPSBAzOasEEsmbMRJ/nTsMRJhnmGkp3RCa/Zw==} 240 + 146 241 '@atcute/repo@1.0.0': 147 242 resolution: {integrity: sha512-3s6VDKMimmYxVXn9OTlYQ7bJGPRcZRyFZ+oF/IFdfm3PsEUxwwSXajw1bG0HVXns1rNgNnDUT0PqMlUd2GnjqA==} 148 243 peerDependencies: ··· 203 298 peerDependenciesMeta: 204 299 workerd: 205 300 optional: true 301 + 302 + '@cloudflare/vite-plugin@1.36.3': 303 + resolution: {integrity: sha512-n3SZhEZQxk4B2xHaCwgXfc7oLkx/4leTxL254P09DK2Qoj1VVOqVELo62CsUYq5dZS+okMdeWqNa13xEOKMs4g==} 304 + peerDependencies: 305 + vite: ^6.1.0 || ^7.0.0 || ^8.0.0 306 + wrangler: ^4.90.0 206 307 207 308 '@cloudflare/workerd-darwin-64@1.20260507.1': 208 309 resolution: {integrity: sha512-S85aMwcaPJUjKWDiG6iMMnioKWtPLACa6m0j/EhHR1GYfVpnxb974cBc6d25L+sf7jHWHJI2u5hGp0UTJ7MtXQ==} ··· 1640 1741 engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1641 1742 hasBin: true 1642 1743 1744 + nanoid@5.1.11: 1745 + resolution: {integrity: sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==} 1746 + engines: {node: ^18 || >=20} 1747 + hasBin: true 1748 + 1643 1749 neotraverse@0.6.18: 1644 1750 resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} 1645 1751 engines: {node: '>= 10'} ··· 2216 2322 2217 2323 snapshots: 2218 2324 2325 + '@astrojs/cloudflare@13.5.0(astro@6.3.1(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.3)(yaml@2.8.4))(jiti@2.7.0)(lightningcss@1.32.0)(workerd@1.20260507.1)(wrangler@4.90.0(@cloudflare/workers-types@4.20260509.1))(yaml@2.8.4)': 2326 + dependencies: 2327 + '@astrojs/internal-helpers': 0.9.0 2328 + '@astrojs/underscore-redirects': 1.0.3 2329 + '@cloudflare/vite-plugin': 1.36.3(vite@7.3.3(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4))(workerd@1.20260507.1)(wrangler@4.90.0(@cloudflare/workers-types@4.20260509.1)) 2330 + astro: 6.3.1(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.3)(yaml@2.8.4) 2331 + piccolore: 0.1.3 2332 + tinyglobby: 0.2.16 2333 + vite: 7.3.3(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4) 2334 + wrangler: 4.90.0(@cloudflare/workers-types@4.20260509.1) 2335 + transitivePeerDependencies: 2336 + - '@types/node' 2337 + - bufferutil 2338 + - jiti 2339 + - less 2340 + - lightningcss 2341 + - sass 2342 + - sass-embedded 2343 + - stylus 2344 + - sugarss 2345 + - terser 2346 + - tsx 2347 + - utf-8-validate 2348 + - workerd 2349 + - yaml 2350 + 2351 + '@astrojs/compiler-binding-darwin-arm64@0.1.10': 2352 + optional: true 2353 + 2354 + '@astrojs/compiler-binding-darwin-x64@0.1.10': 2355 + optional: true 2356 + 2357 + '@astrojs/compiler-binding-linux-arm64-gnu@0.1.10': 2358 + optional: true 2359 + 2360 + '@astrojs/compiler-binding-linux-arm64-musl@0.1.10': 2361 + optional: true 2362 + 2363 + '@astrojs/compiler-binding-linux-x64-gnu@0.1.10': 2364 + optional: true 2365 + 2366 + '@astrojs/compiler-binding-linux-x64-musl@0.1.10': 2367 + optional: true 2368 + 2369 + '@astrojs/compiler-binding-wasm32-wasi@0.1.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': 2370 + dependencies: 2371 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) 2372 + transitivePeerDependencies: 2373 + - '@emnapi/core' 2374 + - '@emnapi/runtime' 2375 + optional: true 2376 + 2377 + '@astrojs/compiler-binding-win32-arm64-msvc@0.1.10': 2378 + optional: true 2379 + 2380 + '@astrojs/compiler-binding-win32-x64-msvc@0.1.10': 2381 + optional: true 2382 + 2383 + '@astrojs/compiler-binding@0.1.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': 2384 + optionalDependencies: 2385 + '@astrojs/compiler-binding-darwin-arm64': 0.1.10 2386 + '@astrojs/compiler-binding-darwin-x64': 0.1.10 2387 + '@astrojs/compiler-binding-linux-arm64-gnu': 0.1.10 2388 + '@astrojs/compiler-binding-linux-arm64-musl': 0.1.10 2389 + '@astrojs/compiler-binding-linux-x64-gnu': 0.1.10 2390 + '@astrojs/compiler-binding-linux-x64-musl': 0.1.10 2391 + '@astrojs/compiler-binding-wasm32-wasi': 0.1.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) 2392 + '@astrojs/compiler-binding-win32-arm64-msvc': 0.1.10 2393 + '@astrojs/compiler-binding-win32-x64-msvc': 0.1.10 2394 + transitivePeerDependencies: 2395 + - '@emnapi/core' 2396 + - '@emnapi/runtime' 2397 + 2398 + '@astrojs/compiler-rs@0.1.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': 2399 + dependencies: 2400 + '@astrojs/compiler-binding': 0.1.10(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) 2401 + transitivePeerDependencies: 2402 + - '@emnapi/core' 2403 + - '@emnapi/runtime' 2404 + 2219 2405 '@astrojs/compiler@4.0.0': {} 2220 2406 2221 2407 '@astrojs/internal-helpers@0.9.0': ··· 2259 2445 is-docker: 4.0.0 2260 2446 is-wsl: 3.1.1 2261 2447 which-pm-runs: 1.1.0 2448 + 2449 + '@astrojs/underscore-redirects@1.0.3': {} 2262 2450 2263 2451 '@atcute/atproto@4.0.0(@atcute/lexicons@2.0.0)': 2264 2452 dependencies: ··· 2284 2472 2285 2473 '@atcute/client@2.0.9': {} 2286 2474 2475 + '@atcute/client@5.0.0(@atcute/lexicons@2.0.0)': 2476 + dependencies: 2477 + '@atcute/identity': 2.0.0(@atcute/lexicons@2.0.0) 2478 + '@atcute/lexicons': 2.0.0 2479 + transitivePeerDependencies: 2480 + - typescript 2481 + 2287 2482 '@atcute/crypto@2.4.1': 2288 2483 dependencies: 2289 2484 '@atcute/multibase': 1.2.0 ··· 2365 2560 dependencies: 2366 2561 '@atcute/uint8array': 1.1.1 2367 2562 2563 + '@atcute/oauth-browser-client@4.0.0(@atcute/identity-resolver@2.0.0(@atcute/identity@2.0.0(@atcute/lexicons@2.0.0))(@atcute/lexicons@2.0.0))(@atcute/lexicons@2.0.0)': 2564 + dependencies: 2565 + '@atcute/client': 5.0.0(@atcute/lexicons@2.0.0) 2566 + '@atcute/identity-resolver': 2.0.0(@atcute/identity@2.0.0(@atcute/lexicons@2.0.0))(@atcute/lexicons@2.0.0) 2567 + '@atcute/lexicons': 2.0.0 2568 + '@atcute/multibase': 1.2.0 2569 + '@atcute/oauth-crypto': 1.0.0 2570 + '@atcute/oauth-types': 1.0.0 2571 + nanoid: 5.1.11 2572 + transitivePeerDependencies: 2573 + - typescript 2574 + 2575 + '@atcute/oauth-crypto@1.0.0': 2576 + dependencies: 2577 + '@atcute/multibase': 1.2.0 2578 + '@atcute/uint8array': 1.1.1 2579 + nanoid: 5.1.11 2580 + valibot: 1.4.0 2581 + transitivePeerDependencies: 2582 + - typescript 2583 + 2584 + '@atcute/oauth-keyset@0.1.1': 2585 + dependencies: 2586 + '@atcute/oauth-crypto': 1.0.0 2587 + transitivePeerDependencies: 2588 + - typescript 2589 + 2590 + '@atcute/oauth-types@1.0.0': 2591 + dependencies: 2592 + '@atcute/identity': 2.0.0(@atcute/lexicons@2.0.0) 2593 + '@atcute/lexicons': 2.0.0 2594 + '@atcute/oauth-keyset': 0.1.1 2595 + valibot: 1.4.0 2596 + transitivePeerDependencies: 2597 + - typescript 2598 + 2368 2599 '@atcute/repo@1.0.0(@atcute/cbor@2.3.3(@atcute/cid@2.4.1))(@atcute/cid@2.4.1)(@atcute/lexicons@2.0.0)': 2369 2600 dependencies: 2370 2601 '@atcute/car': 6.0.0(@atcute/cbor@2.3.3(@atcute/cid@2.4.1))(@atcute/cid@2.4.1) ··· 2425 2656 unenv: 2.0.0-rc.24 2426 2657 optionalDependencies: 2427 2658 workerd: 1.20260507.1 2659 + 2660 + '@cloudflare/vite-plugin@1.36.3(vite@7.3.3(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4))(workerd@1.20260507.1)(wrangler@4.90.0(@cloudflare/workers-types@4.20260509.1))': 2661 + dependencies: 2662 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260507.1) 2663 + miniflare: 4.20260507.1 2664 + unenv: 2.0.0-rc.24 2665 + vite: 7.3.3(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4) 2666 + wrangler: 4.90.0(@cloudflare/workers-types@4.20260509.1) 2667 + ws: 8.18.0 2668 + transitivePeerDependencies: 2669 + - bufferutil 2670 + - utf-8-validate 2671 + - workerd 2428 2672 2429 2673 '@cloudflare/workerd-darwin-64@1.20260507.1': 2430 2674 optional: true ··· 3876 4120 ms@2.1.3: {} 3877 4121 3878 4122 nanoid@3.3.12: {} 4123 + 4124 + nanoid@5.1.11: {} 3879 4125 3880 4126 neotraverse@0.6.18: {} 3881 4127