this repo has no description
0
fork

Configure Feed

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

Add book record to user PDS

modamo-gh 470f6bdc 102faf3d

+822 -106
+5
.gitignore
··· 39 39 # typescript 40 40 *.tsbuildinfo 41 41 next-env.d.ts 42 + 43 + # SQLite databases 44 + *.db 45 + *.db-shm 46 + *.db-wal
+14
app/.well-known/jwks.json/route.ts
··· 1 + import { JoseKey } from "@atproto/oauth-client-node"; 2 + import { NextResponse } from "next/server"; 3 + 4 + const PRIVATE_KEY = process.env.PRIVATE_KEY; 5 + 6 + export async function GET() { 7 + if (!PRIVATE_KEY) { 8 + return NextResponse.json({ keys: [] }); 9 + } 10 + 11 + const key = await JoseKey.fromJWK(JSON.parse(PRIVATE_KEY)); 12 + 13 + return NextResponse.json({ keys: [key.publicJwk] }); 14 + }
+35
app/api/add-book/route.ts
··· 1 + import { getSession } from "@/lib/auth/session"; 2 + import { Agent } from "@atproto/api"; 3 + import { NextRequest, NextResponse } from "next/server"; 4 + 5 + export async function POST(request: NextRequest) { 6 + try { 7 + const { creators, googleBooksId, title } = await request.json(); 8 + const session = await getSession(); 9 + const agent = new Agent(session); 10 + const record = { 11 + createdAt: new Date().toISOString(), 12 + creators, 13 + googleBooksId, 14 + isLendable: true, 15 + title 16 + }; 17 + 18 + await agent.com.atproto.repo.createRecord({ 19 + collection: "xyz.mootpool.item", 20 + record, 21 + repo: session.did 22 + }); 23 + 24 + return NextResponse.json({ success: true }); 25 + } catch (error) { 26 + console.error("Failed to create book record:", error); 27 + 28 + return NextResponse.json( 29 + { 30 + error: "Failed to create book record" 31 + }, 32 + { status: 500 } 33 + ); 34 + } 35 + }
-42
app/api/auth/atproto/callback/route.ts
··· 1 - import { atprotoClient } from "@/lib/atprotoAuth"; 2 - import { NextRequest, NextResponse } from "next/server"; 3 - 4 - const APP_URL = process.env.NEXT_PUBLIC_APP_URL; 5 - 6 - if (!APP_URL) { 7 - throw new Error( 8 - "NEXT_PUBLIC_APP_URL is not set. This is required for OAuth configuration." 9 - ); 10 - } 11 - 12 - export async function GET(request: NextRequest) { 13 - try { 14 - const params = request.nextUrl.searchParams; 15 - const { session } = await atprotoClient.callback(params); 16 - const did = session.sub; 17 - const redirectURL = new URL("/library", APP_URL); 18 - 19 - redirectURL.searchParams.set("atproto_did", session.did); 20 - redirectURL.searchParams.set("auth_status", "success"); 21 - 22 - const response = NextResponse.redirect(redirectURL); 23 - 24 - response.cookies.set("atproto_did", did, { 25 - httpOnly: true, 26 - maxAge: 60 * 60 * 24 * 30, 27 - path: "/", 28 - sameSite: "lax", 29 - secure: false 30 - }); 31 - 32 - return response; 33 - } catch (error) { 34 - console.error("ATProto Callback Error:", error); 35 - 36 - const redirectURL = new URL("/", APP_URL); 37 - 38 - redirectURL.searchParams.set("auth_error", "failed"); 39 - 40 - return NextResponse.redirect(redirectURL); 41 - } 42 - }
-8
app/api/auth/atproto/client-metadata.json/route.ts
··· 1 - import { atprotoClient } from "@/lib/atprotoAuth"; 2 - import { NextResponse } from "next/server"; 3 - 4 - export async function GET() { 5 - return NextResponse.json(atprotoClient.clientMetadata, { 6 - headers: { "Content-Type": "application/json" } 7 - }); 8 - }
-27
app/api/auth/atproto/login/route.ts
··· 1 - import { atprotoClient } from "@/lib/atprotoAuth"; 2 - import { NextRequest, NextResponse } from "next/server"; 3 - 4 - export async function POST(request: NextRequest) { 5 - const { atprotoHandle } = await request.json(); 6 - 7 - 8 - try { 9 - const url = await atprotoClient.authorize(atprotoHandle, { 10 - state: crypto.randomUUID() 11 - }); 12 - 13 - return NextResponse.json({ 14 - url: url.toString() 15 - }); 16 - } catch (error) { 17 - const message = 18 - error instanceof Error 19 - ? error.message 20 - : "An unknown error occurred during the process."; 21 - 22 - return NextResponse.json( 23 - { error: message, success: false }, 24 - { status: 401 } 25 - ); 26 - } 27 - }
+17 -2
app/item/[isbn]/page.tsx
··· 50 50 getBookInfo(); 51 51 }, [isbn]); 52 52 53 + const handleSubmit = async () => { 54 + const response = await fetch("/api/add-book", { 55 + body: JSON.stringify("test"), 56 + headers: { "Content-Type": "application/json" }, 57 + method: "POST" 58 + }); 59 + }; 60 + 53 61 return ( 54 62 <div className="bg-gray-800 grid grid-rows-10 h-screen p-4 w-screen"> 55 63 <header className="flex gap-4 items-center row-span-1 "> ··· 134 142 {details?.volumeInfo.imageLinks.thumbnail ? ( 135 143 <div className="col-span-2 relative rounded-lg row-span-3"> 136 144 <Image 137 - className="object-contain rounded-lg" 145 + className="object-contain rounded-lg" 138 146 src={details.volumeInfo.imageLinks.thumbnail} 139 147 alt={""} 140 148 fill ··· 144 152 <div className="bg-gray-700 border border-gray-600 col-span-2 row-span-3 rounded-lg"></div> 145 153 )} 146 154 <div className="bg-gray-700 border border-gray-600 col-span-3 rounded-lg row-span-5"></div> 147 - <div className="bg-gray-700 border border-gray-600 col-span-2 rounded-lg row-span-2"></div> 155 + <div className="bg-gray-700 border border-gray-600 col-span-2 flex items-center justify-center rounded-lg row-span-2"> 156 + <button 157 + className={`hover:bg-orange-300 bg-orange-400 hover:cursor-pointer px-4 py-2 rounded-lg ${saira.className}`} 158 + onClick={handleSubmit} 159 + > 160 + Add to Library 161 + </button> 162 + </div> 148 163 </main> 149 164 <footer className="row-span-1"></footer> 150 165 </div>
+8
app/oauth-client-metadata.json/route.ts
··· 1 + import { getOAuthClient } from "@/lib/auth/client"; 2 + import { NextResponse } from "next/server"; 3 + 4 + export async function GET() { 5 + const client = await getOAuthClient(); 6 + 7 + return NextResponse.json(client.clientMetadata); 8 + }
+29
app/oauth/callback/route.ts
··· 1 + import { getOAuthClient } from "@/lib/auth/client"; 2 + import { NextRequest, NextResponse } from "next/server"; 3 + 4 + const PUBLIC_URL = process.env.PUBLIC_URL || "http://127.0.0.1:3000"; 5 + 6 + export async function GET(request: NextRequest) { 7 + try { 8 + const params = request.nextUrl.searchParams; 9 + const client = await getOAuthClient(); 10 + const { session } = await client.callback(params); 11 + const response = NextResponse.redirect(new URL("/library", PUBLIC_URL)); 12 + 13 + response.cookies.set("did", session.did, { 14 + httpOnly: true, 15 + maxAge: 60 * 60 * 24 * 7, 16 + path: "/", 17 + sameSite: "lax", 18 + secure: process.env.NODE_ENV === "production" 19 + }); 20 + 21 + return response; 22 + } catch (error) { 23 + console.error("OAuth callback error:", error); 24 + 25 + return NextResponse.redirect( 26 + new URL("/?error=login_failed", PUBLIC_URL) 27 + ); 28 + } 29 + }
+29
app/oauth/login/route.ts
··· 1 + import { getOAuthClient, SCOPE } from "@/lib/auth/client"; 2 + import { NextRequest, NextResponse } from "next/server"; 3 + 4 + export async function POST(request: NextRequest) { 5 + try { 6 + const { handle } = await request.json(); 7 + 8 + if (!handle || typeof handle !== "string") { 9 + return NextResponse.json( 10 + { error: "Handle is required" }, 11 + { status: 400 } 12 + ); 13 + } 14 + 15 + const client = await getOAuthClient(); 16 + const authURL = await client?.authorize(handle, { scope: SCOPE }); 17 + 18 + return NextResponse.json({ redirectURL: authURL?.toString() }); 19 + } catch (error) { 20 + console.error("OAuth login error:", error); 21 + 22 + return NextResponse.json( 23 + { 24 + error: error instanceof Error ? error.message : "Login failed" 25 + }, 26 + { status: 500 } 27 + ); 28 + } 29 + }
+29 -25
app/page.tsx
··· 11 11 const Home = () => { 12 12 const isSelectingRef = useRef(false); 13 13 14 - const [atprotoHandle, setATProtoHandle] = useState(""); 14 + const [handle, setHandle] = useState(""); 15 15 const [handleSuggestions, setHandleSuggestions] = useState([]); 16 16 17 17 useEffect(() => { ··· 20 20 return; 21 21 } 22 22 23 - if (atprotoHandle.length < 3) { 23 + if (handle.length < 3) { 24 24 setHandleSuggestions([]); 25 25 26 26 return; ··· 28 28 29 29 const timer = setTimeout(async () => { 30 30 const response = await fetch( 31 - `/api/search-handles?handle=${atprotoHandle}` 31 + `/api/search-handles?handle=${handle}` 32 32 ); 33 33 const data = await response.json(); 34 34 ··· 36 36 }, 400); 37 37 38 38 return () => clearTimeout(timer); 39 - }, [atprotoHandle]); 39 + }, [handle]); 40 40 41 41 return ( 42 42 <main className="bg-gray-800 flex flex-col h-screen items-center justify-center w-screen"> ··· 44 44 MOOTPOOL 45 45 </h1> 46 46 <div className="flex flex-col gap-2 w-1/4"> 47 - <label htmlFor="atprotoHandle">Your ATProto Handle</label> 47 + <label htmlFor="handle">Your ATProto Handle</label> 48 48 <div> 49 49 <input 50 50 className={`border border-gray-600 focus:border-orange-400 h-12 focus:outline-none p-2 ${ ··· 53 53 : "rounded-lg" 54 54 } w-full`} 55 55 id="" 56 - name="atprotoHandle" 56 + name="handle" 57 57 placeholder="Enter your ATProto handle (e.g. example.blacksky.app)" 58 - onChange={(e) => setATProtoHandle(e.target.value)} 58 + onChange={(e) => setHandle(e.target.value)} 59 59 type="text" 60 - value={atprotoHandle} 60 + value={handle} 61 61 /> 62 62 {handleSuggestions.length ? ( 63 63 <div className="absolute bg-gray-800 border border-t-0 border-gray-600 hover:cursor-pointer flex flex-col gap-2 p-2 rounded-b-lg w-1/4"> ··· 69 69 isSelectingRef.current = true; 70 70 71 71 setHandleSuggestions([]); 72 - setATProtoHandle(suggestion.handle); 72 + setHandle(suggestion.handle); 73 73 }} 74 74 > 75 75 <Image ··· 96 96 className={`${saira.className} bg-orange-400 hover:bg-orange-300 hover:cursor-pointer h-12 rounded-lg`} 97 97 onClick={async () => { 98 98 try { 99 - const response = await fetch( 100 - "/api/auth/atproto/login", 101 - { 102 - body: JSON.stringify({ atprotoHandle }), 103 - headers: { 104 - "Content-Type": "application/json" 105 - }, 106 - method: "POST" 107 - } 108 - ); 99 + const response = await fetch("/oauth/login", { 100 + body: JSON.stringify({ handle }), 101 + headers: { 102 + "Content-Type": "application/json" 103 + }, 104 + method: "POST" 105 + }); 109 106 const data = await response.json(); 110 107 111 - if(response.ok && data.url){ 112 - window.location.href = data.url; 113 - } 114 - else{ 115 - console.error("Login initiation failed:", data.error) 108 + console.log(data); 109 + 110 + if (response.ok && data.redirectURL) { 111 + window.location.href = data.redirectURL; 112 + } else { 113 + console.error( 114 + "Login initiation failed:", 115 + data.error 116 + ); 116 117 } 117 118 } catch (error) { 118 - console.error("Error initiating ATProto OAuth:", error) 119 + console.error( 120 + "Error initiating ATProto OAuth:", 121 + error 122 + ); 119 123 } 120 124 }} 121 125 >
+127
lib/auth/client.ts
··· 1 + import { 2 + buildAtprotoLoopbackClientMetadata, 3 + JoseKey, 4 + Keyset, 5 + NodeOAuthClient, 6 + NodeSavedSession, 7 + NodeSavedState 8 + } from "@atproto/oauth-client-node"; 9 + import { getDB } from "../db/index"; 10 + 11 + declare global { 12 + var _oauthClient: NodeOAuthClient | undefined; 13 + } 14 + 15 + const PRIVATE_KEY = process.env.PRIVATE_KEY; 16 + const PUBLIC_URL = process.env.PUBLIC_URL; 17 + 18 + export const SCOPE = 19 + "atproto repo:xyz.mootpool.item?action=create rpc:app.bsky.actor.getProfile?aud=did:web:api.bsky.app#bsky_appview"; 20 + 21 + const getClientMetadata = () => { 22 + if (PUBLIC_URL) { 23 + return { 24 + client_id: `${PUBLIC_URL}/oauth-client-metadata.json`, 25 + client_name: "mootpool", 26 + client_uri: PUBLIC_URL, 27 + dpop_bound_access_tokens: true, 28 + grant_types: ["authorization_code", "refresh_token"], 29 + jwks_uri: `${PUBLIC_URL}/.well-known/jwks.json`, 30 + redirect_uris: [`${PUBLIC_URL}/oauth/callback`], 31 + response_types: ["code"], 32 + scope: SCOPE, 33 + token_endpoint_auth_method: "private_key_jwt" as const, 34 + token_endpoint_auth_signing_alg: "ES256" as const 35 + }; 36 + } 37 + 38 + return buildAtprotoLoopbackClientMetadata({ 39 + redirect_uris: ["http://127.0.0.1:3000/oauth/callback"], 40 + scope: SCOPE 41 + }); 42 + }; 43 + 44 + const getKeyset = async () => { 45 + if (PUBLIC_URL && PRIVATE_KEY) { 46 + return new Keyset([await JoseKey.fromJWK(JSON.parse(PRIVATE_KEY))]); 47 + } 48 + 49 + return undefined; 50 + }; 51 + 52 + export const getOAuthClient = async () => { 53 + if (globalThis._oauthClient) { 54 + return globalThis._oauthClient; 55 + } 56 + 57 + globalThis._oauthClient = new NodeOAuthClient({ 58 + clientMetadata: getClientMetadata(), 59 + keyset: await getKeyset(), 60 + sessionStore: { 61 + del: async (key: string) => { 62 + const db = getDB(); 63 + 64 + await db 65 + ?.deleteFrom("auth_session") 66 + .where("key", "=", key) 67 + .execute(); 68 + }, 69 + get: async (key: string) => { 70 + const db = getDB(); 71 + const row = await db 72 + ?.selectFrom("auth_session") 73 + .select("value") 74 + .where("key", "=", key) 75 + .executeTakeFirst(); 76 + 77 + return row ? JSON.parse(row.value) : undefined; 78 + }, 79 + set: async (key: string, value: NodeSavedSession) => { 80 + const db = getDB(); 81 + const valueJSON = JSON.stringify(value); 82 + 83 + await db 84 + ?.insertInto("auth_session") 85 + .values({ key, value: valueJSON }) 86 + .onConflict((oc) => 87 + oc.column("key").doUpdateSet({ value: valueJSON }) 88 + ) 89 + .execute(); 90 + } 91 + }, 92 + stateStore: { 93 + del: async (key: string) => { 94 + const db = getDB(); 95 + 96 + await db 97 + ?.deleteFrom("auth_state") 98 + .where("key", "=", key) 99 + .execute(); 100 + }, 101 + get: async (key: string) => { 102 + const db = getDB(); 103 + const row = await db 104 + ?.selectFrom("auth_state") 105 + .select("value") 106 + .where("key", "=", key) 107 + .executeTakeFirst(); 108 + 109 + return row ? JSON.parse(row.value) : undefined; 110 + }, 111 + set: async (key: string, value: NodeSavedState) => { 112 + const db = getDB(); 113 + const valueJSON = JSON.stringify(value); 114 + 115 + await db 116 + ?.insertInto("auth_state") 117 + .values({ key, value: valueJSON }) 118 + .onConflict((oc) => 119 + oc.column("key").doUpdateSet({ value: valueJSON }) 120 + ) 121 + .execute(); 122 + } 123 + } 124 + }); 125 + 126 + return globalThis._oauthClient; 127 + };
+24
lib/auth/session.ts
··· 1 + import { cookies } from "next/headers"; 2 + import { getOAuthClient } from "./client"; 3 + 4 + export const getDID = async () => { 5 + const cookieStore = await cookies(); 6 + 7 + return cookieStore.get("did")?.value ?? null; 8 + }; 9 + 10 + export const getSession = async () => { 11 + const did = await getDID(); 12 + 13 + if (!did) { 14 + return null; 15 + } 16 + 17 + try { 18 + const client = await getOAuthClient(); 19 + 20 + return await client.restore(did); 21 + } catch { 22 + return null; 23 + } 24 + };
+47
lib/db/index.ts
··· 1 + import Database from "better-sqlite3"; 2 + import { Kysely, SqliteDialect } from "kysely"; 3 + 4 + const DATABASE_PATH = process.env.DATABASE_PATH || "app.db"; 5 + 6 + let _db: Kysely<DatabaseSchema> | null = null; 7 + 8 + export const getDB = () => { 9 + if (!_db) { 10 + const sqlite = new Database(DATABASE_PATH); 11 + 12 + sqlite.pragma("journal_mode = WAL"); 13 + 14 + sqlite.exec(` 15 + CREATE TABLE IF NOT EXISTS auth_state ( 16 + key TEXT PRIMARY KEY, 17 + value TEXT NOT NULL 18 + ); 19 + 20 + CREATE TABLE IF NOT EXISTS auth_session ( 21 + key TEXT PRIMARY KEY, 22 + value TEXT NOT NULL 23 + ); 24 + `); 25 + 26 + _db = new Kysely<DatabaseSchema>({ 27 + dialect: new SqliteDialect({ database: sqlite }) 28 + }); 29 + } 30 + 31 + return _db; 32 + }; 33 + 34 + interface AuthSessionTable { 35 + key: string; 36 + value: string; 37 + } 38 + 39 + interface AuthStateTable { 40 + key: string; 41 + value: string; 42 + } 43 + 44 + export interface DatabaseSchema { 45 + auth_session: AuthSessionTable; 46 + auth_state: AuthStateTable; 47 + }
+455 -2
package-lock.json
··· 10 10 "dependencies": { 11 11 "@atproto/api": "^0.18.11", 12 12 "@atproto/oauth-client-node": "^0.3.15", 13 + "better-sqlite3": "^12.6.2", 14 + "kysely": "^0.28.11", 13 15 "next": "16.1.1", 14 16 "react": "19.2.3", 15 17 "react-dom": "19.2.3" 16 18 }, 17 19 "devDependencies": { 18 20 "@tailwindcss/postcss": "^4", 21 + "@types/better-sqlite3": "^7.6.13", 19 22 "@types/node": "^20", 20 23 "@types/react": "^19", 21 24 "@types/react-dom": "^19", ··· 1898 1901 "tslib": "^2.4.0" 1899 1902 } 1900 1903 }, 1904 + "node_modules/@types/better-sqlite3": { 1905 + "version": "7.6.13", 1906 + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", 1907 + "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", 1908 + "dev": true, 1909 + "license": "MIT", 1910 + "dependencies": { 1911 + "@types/node": "*" 1912 + } 1913 + }, 1901 1914 "node_modules/@types/estree": { 1902 1915 "version": "1.0.8", 1903 1916 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", ··· 2786 2799 "dev": true, 2787 2800 "license": "MIT" 2788 2801 }, 2802 + "node_modules/base64-js": { 2803 + "version": "1.5.1", 2804 + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 2805 + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 2806 + "funding": [ 2807 + { 2808 + "type": "github", 2809 + "url": "https://github.com/sponsors/feross" 2810 + }, 2811 + { 2812 + "type": "patreon", 2813 + "url": "https://www.patreon.com/feross" 2814 + }, 2815 + { 2816 + "type": "consulting", 2817 + "url": "https://feross.org/support" 2818 + } 2819 + ], 2820 + "license": "MIT" 2821 + }, 2789 2822 "node_modules/baseline-browser-mapping": { 2790 2823 "version": "2.9.12", 2791 2824 "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.12.tgz", ··· 2795 2828 "baseline-browser-mapping": "dist/cli.js" 2796 2829 } 2797 2830 }, 2831 + "node_modules/better-sqlite3": { 2832 + "version": "12.6.2", 2833 + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.6.2.tgz", 2834 + "integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==", 2835 + "hasInstallScript": true, 2836 + "license": "MIT", 2837 + "dependencies": { 2838 + "bindings": "^1.5.0", 2839 + "prebuild-install": "^7.1.1" 2840 + }, 2841 + "engines": { 2842 + "node": "20.x || 22.x || 23.x || 24.x || 25.x" 2843 + } 2844 + }, 2845 + "node_modules/bindings": { 2846 + "version": "1.5.0", 2847 + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 2848 + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 2849 + "license": "MIT", 2850 + "dependencies": { 2851 + "file-uri-to-path": "1.0.0" 2852 + } 2853 + }, 2854 + "node_modules/bl": { 2855 + "version": "4.1.0", 2856 + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 2857 + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 2858 + "license": "MIT", 2859 + "dependencies": { 2860 + "buffer": "^5.5.0", 2861 + "inherits": "^2.0.4", 2862 + "readable-stream": "^3.4.0" 2863 + } 2864 + }, 2798 2865 "node_modules/brace-expansion": { 2799 2866 "version": "1.1.12", 2800 2867 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", ··· 2853 2920 "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 2854 2921 } 2855 2922 }, 2923 + "node_modules/buffer": { 2924 + "version": "5.7.1", 2925 + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 2926 + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 2927 + "funding": [ 2928 + { 2929 + "type": "github", 2930 + "url": "https://github.com/sponsors/feross" 2931 + }, 2932 + { 2933 + "type": "patreon", 2934 + "url": "https://www.patreon.com/feross" 2935 + }, 2936 + { 2937 + "type": "consulting", 2938 + "url": "https://feross.org/support" 2939 + } 2940 + ], 2941 + "license": "MIT", 2942 + "dependencies": { 2943 + "base64-js": "^1.3.1", 2944 + "ieee754": "^1.1.13" 2945 + } 2946 + }, 2856 2947 "node_modules/call-bind": { 2857 2948 "version": "1.0.8", 2858 2949 "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", ··· 2949 3040 "funding": { 2950 3041 "url": "https://github.com/chalk/chalk?sponsor=1" 2951 3042 } 3043 + }, 3044 + "node_modules/chownr": { 3045 + "version": "1.1.4", 3046 + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 3047 + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", 3048 + "license": "ISC" 2952 3049 }, 2953 3050 "node_modules/client-only": { 2954 3051 "version": "0.0.1", ··· 3102 3199 } 3103 3200 } 3104 3201 }, 3202 + "node_modules/decompress-response": { 3203 + "version": "6.0.0", 3204 + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", 3205 + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", 3206 + "license": "MIT", 3207 + "dependencies": { 3208 + "mimic-response": "^3.1.0" 3209 + }, 3210 + "engines": { 3211 + "node": ">=10" 3212 + }, 3213 + "funding": { 3214 + "url": "https://github.com/sponsors/sindresorhus" 3215 + } 3216 + }, 3217 + "node_modules/deep-extend": { 3218 + "version": "0.6.0", 3219 + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 3220 + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 3221 + "license": "MIT", 3222 + "engines": { 3223 + "node": ">=4.0.0" 3224 + } 3225 + }, 3105 3226 "node_modules/deep-is": { 3106 3227 "version": "0.1.4", 3107 3228 "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", ··· 3149 3270 "version": "2.1.2", 3150 3271 "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", 3151 3272 "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", 3152 - "devOptional": true, 3153 3273 "license": "Apache-2.0", 3154 3274 "engines": { 3155 3275 "node": ">=8" ··· 3196 3316 "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 3197 3317 "dev": true, 3198 3318 "license": "MIT" 3319 + }, 3320 + "node_modules/end-of-stream": { 3321 + "version": "1.4.5", 3322 + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", 3323 + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", 3324 + "license": "MIT", 3325 + "dependencies": { 3326 + "once": "^1.4.0" 3327 + } 3199 3328 }, 3200 3329 "node_modules/enhanced-resolve": { 3201 3330 "version": "5.18.4", ··· 3835 3964 "node": ">=0.10.0" 3836 3965 } 3837 3966 }, 3967 + "node_modules/expand-template": { 3968 + "version": "2.0.3", 3969 + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", 3970 + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", 3971 + "license": "(MIT OR WTFPL)", 3972 + "engines": { 3973 + "node": ">=6" 3974 + } 3975 + }, 3838 3976 "node_modules/fast-deep-equal": { 3839 3977 "version": "3.1.3", 3840 3978 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", ··· 3909 4047 "node": ">=16.0.0" 3910 4048 } 3911 4049 }, 4050 + "node_modules/file-uri-to-path": { 4051 + "version": "1.0.0", 4052 + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 4053 + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", 4054 + "license": "MIT" 4055 + }, 3912 4056 "node_modules/fill-range": { 3913 4057 "version": "7.1.1", 3914 4058 "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", ··· 3975 4119 "funding": { 3976 4120 "url": "https://github.com/sponsors/ljharb" 3977 4121 } 4122 + }, 4123 + "node_modules/fs-constants": { 4124 + "version": "1.0.0", 4125 + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 4126 + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", 4127 + "license": "MIT" 3978 4128 }, 3979 4129 "node_modules/function-bind": { 3980 4130 "version": "1.1.2", ··· 4107 4257 "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 4108 4258 } 4109 4259 }, 4260 + "node_modules/github-from-package": { 4261 + "version": "0.0.0", 4262 + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", 4263 + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", 4264 + "license": "MIT" 4265 + }, 4110 4266 "node_modules/glob-parent": { 4111 4267 "version": "6.0.2", 4112 4268 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", ··· 4281 4437 "hermes-estree": "0.25.1" 4282 4438 } 4283 4439 }, 4440 + "node_modules/ieee754": { 4441 + "version": "1.2.1", 4442 + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 4443 + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 4444 + "funding": [ 4445 + { 4446 + "type": "github", 4447 + "url": "https://github.com/sponsors/feross" 4448 + }, 4449 + { 4450 + "type": "patreon", 4451 + "url": "https://www.patreon.com/feross" 4452 + }, 4453 + { 4454 + "type": "consulting", 4455 + "url": "https://feross.org/support" 4456 + } 4457 + ], 4458 + "license": "BSD-3-Clause" 4459 + }, 4284 4460 "node_modules/ignore": { 4285 4461 "version": "5.3.2", 4286 4462 "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", ··· 4317 4493 "engines": { 4318 4494 "node": ">=0.8.19" 4319 4495 } 4496 + }, 4497 + "node_modules/inherits": { 4498 + "version": "2.0.4", 4499 + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 4500 + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 4501 + "license": "ISC" 4502 + }, 4503 + "node_modules/ini": { 4504 + "version": "1.3.8", 4505 + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 4506 + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 4507 + "license": "ISC" 4320 4508 }, 4321 4509 "node_modules/internal-slot": { 4322 4510 "version": "1.1.0", ··· 4907 5095 "json-buffer": "3.0.1" 4908 5096 } 4909 5097 }, 5098 + "node_modules/kysely": { 5099 + "version": "0.28.11", 5100 + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.11.tgz", 5101 + "integrity": "sha512-zpGIFg0HuoC893rIjYX1BETkVWdDnzTzF5e0kWXJFg5lE0k1/LfNWBejrcnOFu8Q2Rfq/hTDTU7XLUM8QOrpzg==", 5102 + "license": "MIT", 5103 + "engines": { 5104 + "node": ">=20.0.0" 5105 + } 5106 + }, 4910 5107 "node_modules/language-subtag-registry": { 4911 5108 "version": "0.3.23", 4912 5109 "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", ··· 5292 5489 "node": ">=8.6" 5293 5490 } 5294 5491 }, 5492 + "node_modules/mimic-response": { 5493 + "version": "3.1.0", 5494 + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", 5495 + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", 5496 + "license": "MIT", 5497 + "engines": { 5498 + "node": ">=10" 5499 + }, 5500 + "funding": { 5501 + "url": "https://github.com/sponsors/sindresorhus" 5502 + } 5503 + }, 5295 5504 "node_modules/minimatch": { 5296 5505 "version": "3.1.2", 5297 5506 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", ··· 5309 5518 "version": "1.2.8", 5310 5519 "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 5311 5520 "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 5312 - "dev": true, 5313 5521 "license": "MIT", 5314 5522 "funding": { 5315 5523 "url": "https://github.com/sponsors/ljharb" 5316 5524 } 5317 5525 }, 5526 + "node_modules/mkdirp-classic": { 5527 + "version": "0.5.3", 5528 + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 5529 + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", 5530 + "license": "MIT" 5531 + }, 5318 5532 "node_modules/ms": { 5319 5533 "version": "2.1.3", 5320 5534 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", ··· 5345 5559 "engines": { 5346 5560 "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 5347 5561 } 5562 + }, 5563 + "node_modules/napi-build-utils": { 5564 + "version": "2.0.0", 5565 + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", 5566 + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", 5567 + "license": "MIT" 5348 5568 }, 5349 5569 "node_modules/napi-postinstall": { 5350 5570 "version": "0.3.4", ··· 5450 5670 "node": "^10 || ^12 || >=14" 5451 5671 } 5452 5672 }, 5673 + "node_modules/node-abi": { 5674 + "version": "3.87.0", 5675 + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", 5676 + "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", 5677 + "license": "MIT", 5678 + "dependencies": { 5679 + "semver": "^7.3.5" 5680 + }, 5681 + "engines": { 5682 + "node": ">=10" 5683 + } 5684 + }, 5685 + "node_modules/node-abi/node_modules/semver": { 5686 + "version": "7.7.4", 5687 + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", 5688 + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", 5689 + "license": "ISC", 5690 + "bin": { 5691 + "semver": "bin/semver.js" 5692 + }, 5693 + "engines": { 5694 + "node": ">=10" 5695 + } 5696 + }, 5453 5697 "node_modules/node-releases": { 5454 5698 "version": "2.0.27", 5455 5699 "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", ··· 5578 5822 }, 5579 5823 "funding": { 5580 5824 "url": "https://github.com/sponsors/ljharb" 5825 + } 5826 + }, 5827 + "node_modules/once": { 5828 + "version": "1.4.0", 5829 + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 5830 + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 5831 + "license": "ISC", 5832 + "dependencies": { 5833 + "wrappy": "1" 5581 5834 } 5582 5835 }, 5583 5836 "node_modules/optionator": { ··· 5746 5999 "node": "^10 || ^12 || >=14" 5747 6000 } 5748 6001 }, 6002 + "node_modules/prebuild-install": { 6003 + "version": "7.1.3", 6004 + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", 6005 + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", 6006 + "license": "MIT", 6007 + "dependencies": { 6008 + "detect-libc": "^2.0.0", 6009 + "expand-template": "^2.0.3", 6010 + "github-from-package": "0.0.0", 6011 + "minimist": "^1.2.3", 6012 + "mkdirp-classic": "^0.5.3", 6013 + "napi-build-utils": "^2.0.0", 6014 + "node-abi": "^3.3.0", 6015 + "pump": "^3.0.0", 6016 + "rc": "^1.2.7", 6017 + "simple-get": "^4.0.0", 6018 + "tar-fs": "^2.0.0", 6019 + "tunnel-agent": "^0.6.0" 6020 + }, 6021 + "bin": { 6022 + "prebuild-install": "bin.js" 6023 + }, 6024 + "engines": { 6025 + "node": ">=10" 6026 + } 6027 + }, 5749 6028 "node_modules/prelude-ls": { 5750 6029 "version": "1.2.1", 5751 6030 "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", ··· 5768 6047 "react-is": "^16.13.1" 5769 6048 } 5770 6049 }, 6050 + "node_modules/pump": { 6051 + "version": "3.0.3", 6052 + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", 6053 + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", 6054 + "license": "MIT", 6055 + "dependencies": { 6056 + "end-of-stream": "^1.1.0", 6057 + "once": "^1.3.1" 6058 + } 6059 + }, 5771 6060 "node_modules/punycode": { 5772 6061 "version": "2.3.1", 5773 6062 "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", ··· 5799 6088 ], 5800 6089 "license": "MIT" 5801 6090 }, 6091 + "node_modules/rc": { 6092 + "version": "1.2.8", 6093 + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 6094 + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 6095 + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", 6096 + "dependencies": { 6097 + "deep-extend": "^0.6.0", 6098 + "ini": "~1.3.0", 6099 + "minimist": "^1.2.0", 6100 + "strip-json-comments": "~2.0.1" 6101 + }, 6102 + "bin": { 6103 + "rc": "cli.js" 6104 + } 6105 + }, 6106 + "node_modules/rc/node_modules/strip-json-comments": { 6107 + "version": "2.0.1", 6108 + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 6109 + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 6110 + "license": "MIT", 6111 + "engines": { 6112 + "node": ">=0.10.0" 6113 + } 6114 + }, 5802 6115 "node_modules/react": { 5803 6116 "version": "19.2.3", 5804 6117 "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", ··· 5826 6139 "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", 5827 6140 "dev": true, 5828 6141 "license": "MIT" 6142 + }, 6143 + "node_modules/readable-stream": { 6144 + "version": "3.6.2", 6145 + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 6146 + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 6147 + "license": "MIT", 6148 + "dependencies": { 6149 + "inherits": "^2.0.3", 6150 + "string_decoder": "^1.1.1", 6151 + "util-deprecate": "^1.0.1" 6152 + }, 6153 + "engines": { 6154 + "node": ">= 6" 6155 + } 5829 6156 }, 5830 6157 "node_modules/reflect.getprototypeof": { 5831 6158 "version": "1.0.10", ··· 5967 6294 "url": "https://github.com/sponsors/ljharb" 5968 6295 } 5969 6296 }, 6297 + "node_modules/safe-buffer": { 6298 + "version": "5.2.1", 6299 + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 6300 + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 6301 + "funding": [ 6302 + { 6303 + "type": "github", 6304 + "url": "https://github.com/sponsors/feross" 6305 + }, 6306 + { 6307 + "type": "patreon", 6308 + "url": "https://www.patreon.com/feross" 6309 + }, 6310 + { 6311 + "type": "consulting", 6312 + "url": "https://feross.org/support" 6313 + } 6314 + ], 6315 + "license": "MIT" 6316 + }, 5970 6317 "node_modules/safe-push-apply": { 5971 6318 "version": "1.0.0", 5972 6319 "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", ··· 6224 6571 "url": "https://github.com/sponsors/ljharb" 6225 6572 } 6226 6573 }, 6574 + "node_modules/simple-concat": { 6575 + "version": "1.0.1", 6576 + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", 6577 + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", 6578 + "funding": [ 6579 + { 6580 + "type": "github", 6581 + "url": "https://github.com/sponsors/feross" 6582 + }, 6583 + { 6584 + "type": "patreon", 6585 + "url": "https://www.patreon.com/feross" 6586 + }, 6587 + { 6588 + "type": "consulting", 6589 + "url": "https://feross.org/support" 6590 + } 6591 + ], 6592 + "license": "MIT" 6593 + }, 6594 + "node_modules/simple-get": { 6595 + "version": "4.0.1", 6596 + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", 6597 + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", 6598 + "funding": [ 6599 + { 6600 + "type": "github", 6601 + "url": "https://github.com/sponsors/feross" 6602 + }, 6603 + { 6604 + "type": "patreon", 6605 + "url": "https://www.patreon.com/feross" 6606 + }, 6607 + { 6608 + "type": "consulting", 6609 + "url": "https://feross.org/support" 6610 + } 6611 + ], 6612 + "license": "MIT", 6613 + "dependencies": { 6614 + "decompress-response": "^6.0.0", 6615 + "once": "^1.3.1", 6616 + "simple-concat": "^1.0.0" 6617 + } 6618 + }, 6227 6619 "node_modules/source-map-js": { 6228 6620 "version": "1.2.1", 6229 6621 "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", ··· 6254 6646 "node": ">= 0.4" 6255 6647 } 6256 6648 }, 6649 + "node_modules/string_decoder": { 6650 + "version": "1.3.0", 6651 + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 6652 + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 6653 + "license": "MIT", 6654 + "dependencies": { 6655 + "safe-buffer": "~5.2.0" 6656 + } 6657 + }, 6257 6658 "node_modules/string.prototype.includes": { 6258 6659 "version": "2.0.1", 6259 6660 "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", ··· 6460 6861 "url": "https://opencollective.com/webpack" 6461 6862 } 6462 6863 }, 6864 + "node_modules/tar-fs": { 6865 + "version": "2.1.4", 6866 + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", 6867 + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", 6868 + "license": "MIT", 6869 + "dependencies": { 6870 + "chownr": "^1.1.1", 6871 + "mkdirp-classic": "^0.5.2", 6872 + "pump": "^3.0.0", 6873 + "tar-stream": "^2.1.4" 6874 + } 6875 + }, 6876 + "node_modules/tar-stream": { 6877 + "version": "2.2.0", 6878 + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 6879 + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 6880 + "license": "MIT", 6881 + "dependencies": { 6882 + "bl": "^4.0.3", 6883 + "end-of-stream": "^1.4.1", 6884 + "fs-constants": "^1.0.0", 6885 + "inherits": "^2.0.3", 6886 + "readable-stream": "^3.1.1" 6887 + }, 6888 + "engines": { 6889 + "node": ">=6" 6890 + } 6891 + }, 6463 6892 "node_modules/tinyglobby": { 6464 6893 "version": "0.2.15", 6465 6894 "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", ··· 6574 7003 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 6575 7004 "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 6576 7005 "license": "0BSD" 7006 + }, 7007 + "node_modules/tunnel-agent": { 7008 + "version": "0.6.0", 7009 + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 7010 + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", 7011 + "license": "Apache-2.0", 7012 + "dependencies": { 7013 + "safe-buffer": "^5.0.1" 7014 + }, 7015 + "engines": { 7016 + "node": "*" 7017 + } 6577 7018 }, 6578 7019 "node_modules/type-check": { 6579 7020 "version": "0.4.0", ··· 6830 7271 "punycode": "^2.1.0" 6831 7272 } 6832 7273 }, 7274 + "node_modules/util-deprecate": { 7275 + "version": "1.0.2", 7276 + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 7277 + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 7278 + "license": "MIT" 7279 + }, 6833 7280 "node_modules/which": { 6834 7281 "version": "2.0.2", 6835 7282 "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", ··· 6944 7391 "engines": { 6945 7392 "node": ">=0.10.0" 6946 7393 } 7394 + }, 7395 + "node_modules/wrappy": { 7396 + "version": "1.0.2", 7397 + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 7398 + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 7399 + "license": "ISC" 6947 7400 }, 6948 7401 "node_modules/yallist": { 6949 7402 "version": "3.1.1",
+3
package.json
··· 11 11 "dependencies": { 12 12 "@atproto/api": "^0.18.11", 13 13 "@atproto/oauth-client-node": "^0.3.15", 14 + "better-sqlite3": "^12.6.2", 15 + "kysely": "^0.28.11", 14 16 "next": "16.1.1", 15 17 "react": "19.2.3", 16 18 "react-dom": "19.2.3" 17 19 }, 18 20 "devDependencies": { 19 21 "@tailwindcss/postcss": "^4", 22 + "@types/better-sqlite3": "^7.6.13", 20 23 "@types/node": "^20", 21 24 "@types/react": "^19", 22 25 "@types/react-dom": "^19",