a tool for shared writing and social publishing

Feature/bsky pubs/demo (#131)

* WIP

* add super basic lexicon functionality

* WIP

* init publications review view

* added some small state stuff in you're already subbed

* added a writer home and did more to the subscribe flow

* create publication flow (and some updates to the imput with label
component)

* add basic bluesky pub integration!

A lexicon! Oauth! All the stuff!

* rename appview start script

* set oauth client redirect state

* wired up the home pub list

* wiring up the create pub flow

* add heading and image blocks, handle image upload

* moved some shit around in the nav to get urls to work, wired up the pub
page

* added publish button to leaflets

* add drafts and publish button

* add subscribing via email!

* wired up post list and post page, styled pst page

* cleaning up some comments

* add runner to appview

* clean up

* move oauth-metadata out from route file

* add email to subscribers!

---------

Co-authored-by: celine <celine@hyperlink.academy>

authored by awarm.space

celine and committed by
GitHub
cf79767d c6377a9f

+8701 -140
+5 -2
actions/createIdentity.ts
··· 12 12 import { v7 } from "uuid"; 13 13 import { sql } from "drizzle-orm"; 14 14 import { cookies } from "next/headers"; 15 - export async function createIdentity(db: PostgresJsDatabase) { 15 + export async function createIdentity( 16 + db: PostgresJsDatabase, 17 + data?: { email?: string; atp_did?: string }, 18 + ) { 16 19 return db.transaction(async (tx) => { 17 20 // Create a new entity set 18 21 let [entity_set] = await tx.insert(entity_sets).values({}).returning(); ··· 41 44 .returning(); 42 45 let [identity] = await tx 43 46 .insert(identities) 44 - .values({ home_page: permissionToken.id }) 47 + .values({ home_page: permissionToken.id, ...data }) 45 48 .returning(); 46 49 return identity; 47 50 });
+22
actions/createPublication.ts
··· 1 + "use server"; 2 + import { TID } from "@atproto/common"; 3 + import { AtpBaseClient } from "lexicons/src"; 4 + import { createOauthClient } from "src/atproto-oauth"; 5 + import { getIdentityData } from "actions/getIdentityData"; 6 + 7 + export async function createPublication(name: string) { 8 + const oauthClient = await createOauthClient(); 9 + let identity = await getIdentityData(); 10 + if (!identity || !identity.atp_did) return; 11 + let credentialSession = await oauthClient.restore(identity.atp_did); 12 + let agent = new AtpBaseClient( 13 + credentialSession.fetchHandler.bind(credentialSession), 14 + ); 15 + let result = await agent.pub.leaflet.publication.create( 16 + { repo: credentialSession.did!, rkey: TID.nextStr(), validate: false }, 17 + { 18 + name, 19 + }, 20 + ); 21 + console.log(result); 22 + }
+16
actions/createPublicationDraft.ts
··· 1 + "use server"; 2 + import { getIdentityData } from "actions/getIdentityData"; 3 + import { createNewLeaflet } from "./createNewLeaflet"; 4 + import { supabaseServerClient } from "supabase/serverClient"; 5 + 6 + export async function createPublicationDraft(publication_uri: string) { 7 + let identity = await getIdentityData(); 8 + if (!identity || !identity.atp_did) return null; 9 + let newLeaflet = await createNewLeaflet("doc", false); 10 + console.log( 11 + await supabaseServerClient 12 + .from("leaflets_in_publications") 13 + .insert({ publication: publication_uri, leaflet: newLeaflet, doc: null }), 14 + ); 15 + return newLeaflet; 16 + }
+33 -3
actions/emailAuth.ts
··· 6 6 import { email_auth_tokens, identities } from "drizzle/schema"; 7 7 import { and, eq } from "drizzle-orm"; 8 8 import { cookies } from "next/headers"; 9 + import { createIdentity } from "./createIdentity"; 9 10 10 11 async function sendAuthCode(email: string, code: string) { 11 - console.log(code); 12 12 if (process.env.NODE_ENV === "development") { 13 13 console.log("Auth code:", code); 14 14 return; ··· 72 72 .from(email_auth_tokens) 73 73 .where(eq(email_auth_tokens.id, tokenId)); 74 74 75 - if (!token) { 75 + if (!token || !token.email) { 76 + console.log("no token?"); 76 77 client.end(); 77 78 return null; 78 79 } 79 80 80 81 if (token.confirmation_code !== code) { 82 + console.log("wrong code???"); 81 83 client.end(); 82 84 return null; 83 85 } 84 86 85 87 if (token.confirmed) { 88 + console.log("already confirmed?????"); 86 89 client.end(); 87 90 return null; 88 91 } 92 + let authToken = cookies().get("auth_token"); 93 + if (authToken) { 94 + let [existingToken] = await db 95 + .select() 96 + .from(email_auth_tokens) 97 + .rightJoin(identities, eq(identities.id, email_auth_tokens.identity)) 98 + .where(eq(email_auth_tokens.id, authToken.value)); 89 99 100 + if (existingToken) { 101 + if (existingToken.identities?.email) { 102 + console.log("wat"); 103 + } 104 + await db 105 + .update(identities) 106 + .set({ email: token.email }) 107 + .where(eq(identities.id, existingToken.identities.id)); 108 + client.end(); 109 + return existingToken; 110 + } 111 + } 112 + 113 + let identityID; 90 114 let [identity] = await db 91 115 .select() 92 116 .from(identities) 93 117 .where(eq(identities.email, token.email)); 118 + if (!identity) { 119 + let newIdentity = await createIdentity(db, { email: token.email }); 120 + identityID = newIdentity.id; 121 + } else { 122 + identityID = identity.id; 123 + } 94 124 95 125 const [confirmedToken] = await db 96 126 .update(email_auth_tokens) 97 127 .set({ 98 128 confirmed: true, 99 - identity: identity?.id, 129 + identity: identityID, 100 130 }) 101 131 .where( 102 132 and(
+20 -1
actions/getIdentityData.ts
··· 1 1 "use server"; 2 2 3 + import { IdResolver } from "@atproto/identity"; 3 4 import { createServerClient } from "@supabase/ssr"; 4 5 import { cookies } from "next/headers"; 5 6 import { Database } from "supabase/database.types"; ··· 9 10 process.env.SUPABASE_SERVICE_ROLE_KEY as string, 10 11 { cookies: {} }, 11 12 ); 13 + let idResolver = new IdResolver(); 12 14 export async function getIdentityData() { 13 15 let cookieStore = cookies(); 14 16 let auth_token = cookieStore.get("auth_token")?.value; ··· 19 21 `*, 20 22 identities( 21 23 *, 24 + subscribers_to_publications(*), 22 25 custom_domains(*), 23 26 home_leaflet:permission_tokens!identities_home_page_fkey(*, permission_token_rights(*)), 24 27 permission_token_on_homepage(created_at, permission_tokens!inner(id, root_entity, permission_token_rights(*))) ··· 29 32 .single() 30 33 : null; 31 34 if (!auth_res?.data?.identities) return null; 32 - return auth_res.data.identities; 35 + if (auth_res.data.identities.atp_did) { 36 + //I should create a relationship table so I can do this in the above query 37 + let { data: publications } = await supabase 38 + .from("publications") 39 + .select("*") 40 + .eq("identity_did", auth_res.data.identities.atp_did); 41 + let resolved_did = await idResolver.did.resolve( 42 + auth_res.data.identities.atp_did, 43 + ); 44 + return { 45 + ...auth_res.data.identities, 46 + publications: publications || [], 47 + resolved_did, 48 + }; 49 + } 50 + 51 + return { ...auth_res.data.identities, publications: [], resolved_did: null }; 33 52 }
+4 -34
actions/login.ts
··· 15 15 import { cookies } from "next/headers"; 16 16 import { redirect } from "next/navigation"; 17 17 import { v7 } from "uuid"; 18 + import { createIdentity } from "./createIdentity"; 18 19 19 20 export async function loginWithEmailToken( 20 21 localLeaflets: { token: { id: string }; added_at: string }[], ··· 34 35 eq(email_auth_tokens.confirmed, true), 35 36 ), 36 37 ); 37 - if (!token) return null; 38 + if (!token || !token.email) return null; 38 39 if (token.identity) { 39 40 let id = token.identity; 40 41 if (localLeaflets.length > 0) ··· 75 76 identity = existingIdentityFromCookie; 76 77 } 77 78 } else { 78 - // Create a new entity set 79 - let [entity_set] = await tx.insert(entity_sets).values({}).returning(); 80 - // Create a root-entity 81 - let [entity] = await tx 82 - .insert(entities) 83 - // And add it to that permission set 84 - .values({ set: entity_set.id, id: v7() }) 85 - .returning(); 86 - //Create a new permission token 87 - let [permissionToken] = await tx 88 - .insert(permission_tokens) 89 - .values({ root_entity: entity.id }) 90 - .returning(); 91 - //and give it all the permission on that entity set 92 - let [rights] = await tx 93 - .insert(permission_token_rights) 94 - .values({ 95 - token: permissionToken.id, 96 - entity_set: entity_set.id, 97 - read: true, 98 - write: true, 99 - create_token: true, 100 - change_entity_set: true, 101 - }) 102 - .returning(); 103 - let [newIdentity] = await tx 104 - .insert(identities) 105 - .values({ 106 - home_page: permissionToken.id, 107 - email: token.email, 108 - }) 109 - .returning(); 110 - identity = newIdentity; 79 + // Create a new identity 80 + identity = await createIdentity(tx, { email: token.email }); 111 81 } 112 82 } 113 83
+267
actions/publishToPublication.ts
··· 1 + "use server"; 2 + 3 + import * as Y from "yjs"; 4 + import * as base64 from "base64-js"; 5 + import { createOauthClient } from "src/atproto-oauth"; 6 + import { getIdentityData } from "actions/getIdentityData"; 7 + import { 8 + AtpBaseClient, 9 + PubLeafletBlocksHeader, 10 + PubLeafletBlocksText, 11 + PubLeafletDocument, 12 + PubLeafletPagesLinearDocument, 13 + } from "lexicons/src"; 14 + import { Block } from "components/Blocks/Block"; 15 + import { TID } from "@atproto/common"; 16 + import { supabaseServerClient } from "supabase/serverClient"; 17 + import { scanIndex, scanIndexLocal } from "src/replicache/utils"; 18 + import { Fact } from "src/replicache"; 19 + import { Attributes } from "src/replicache/attributes"; 20 + import { YJSFragmentToString } from "components/Blocks/TextBlock/RenderYJSFragment"; 21 + import { ids } from "lexicons/src/lexicons"; 22 + import { OmitKey } from "lexicons/src/util"; 23 + import { BlobRef } from "@atproto/lexicon"; 24 + import { IdResolver } from "@atproto/identity"; 25 + import { AtUri } from "@atproto/syntax"; 26 + 27 + const idResolver = new IdResolver(); 28 + export async function publishToPublication( 29 + root_entity: string, 30 + blocks: Block[], 31 + publication_uri: string, 32 + ) { 33 + const oauthClient = await createOauthClient(); 34 + let identity = await getIdentityData(); 35 + if (!identity || !identity.atp_did) return null; 36 + 37 + let credentialSession = await oauthClient.restore(identity.atp_did); 38 + let agent = new AtpBaseClient( 39 + credentialSession.fetchHandler.bind(credentialSession), 40 + ); 41 + let { data } = await supabaseServerClient.rpc("get_facts", { 42 + root: root_entity, 43 + }); 44 + console.log(data); 45 + 46 + let scan = scanIndexLocal( 47 + (data as unknown as Fact<keyof typeof Attributes>[]) || [], 48 + ); 49 + const getBlockContent = (b: string) => { 50 + let [content] = scan.eav(b, "block/text"); 51 + if (!content) return ""; 52 + let doc = new Y.Doc(); 53 + const update = base64.toByteArray(content.data.value); 54 + Y.applyUpdate(doc, update); 55 + let nodes = doc.getXmlElement("prosemirror").toArray(); 56 + let stringValue = YJSFragmentToString(nodes[0]); 57 + return stringValue; 58 + }; 59 + let images = blocks 60 + .filter((b) => b.type === "image") 61 + .map((b) => scan.eav(b.value, "block/image")[0]); 62 + let imageMap = new Map<string, BlobRef>(); 63 + await Promise.all( 64 + images.map(async (b) => { 65 + let data = await fetch(b.data.src); 66 + let binary = await data.blob(); 67 + let blob = await agent.com.atproto.repo.uploadBlob(binary, { 68 + headers: { "Content-Type": binary.type }, 69 + }); 70 + console.log(blob); 71 + imageMap.set(b.data.src, blob.data.blob); 72 + }), 73 + ); 74 + 75 + let title = "Untitled"; 76 + let titleBlock = blocks.find((f) => f.type === "heading"); 77 + if (titleBlock) title = getBlockContent(titleBlock.value); 78 + let b: PubLeafletPagesLinearDocument.Block[] = blocksToRecord( 79 + blocks, 80 + imageMap, 81 + scan, 82 + ); 83 + 84 + let record: OmitKey<PubLeafletDocument.Record, "$type"> = { 85 + author: credentialSession.did!, 86 + title, 87 + publication: publication_uri, 88 + pages: [ 89 + { 90 + $type: "pub.leaflet.pages.linearDocument", 91 + blocks: b, 92 + }, 93 + ], 94 + }; 95 + let rkey = TID.nextStr(); 96 + let result = await agent.pub.leaflet.document.create( 97 + { repo: credentialSession.did!, rkey, validate: false }, 98 + record, 99 + ); 100 + let html = blocksToHtml(blocks, imageMap, scan, publication_uri); 101 + await sendPostToEmailSubscribers(publication_uri, { title, content: html }); 102 + let handle = await idResolver.did.resolve(credentialSession.did!); 103 + return { handle, rkey }; 104 + } 105 + 106 + function blocksToRecord( 107 + blocks: Block[], 108 + imageMap: Map<string, BlobRef>, 109 + scan: ReturnType<typeof scanIndexLocal>, 110 + ) { 111 + const getBlockContent = (b: string) => { 112 + let [content] = scan.eav(b, "block/text"); 113 + if (!content) return ""; 114 + let doc = new Y.Doc(); 115 + const update = base64.toByteArray(content.data.value); 116 + Y.applyUpdate(doc, update); 117 + let nodes = doc.getXmlElement("prosemirror").toArray(); 118 + let stringValue = YJSFragmentToString(nodes[0]); 119 + return stringValue; 120 + }; 121 + return blocks.flatMap((b) => { 122 + if (b.type !== "text" && b.type !== "heading" && b.type !== "image") 123 + return []; 124 + if (b.type === "heading") { 125 + let [headingLevel] = scan.eav(b.value, "block/heading-level"); 126 + 127 + let stringValue = getBlockContent(b.value); 128 + return [ 129 + { 130 + $type: "pub.leaflet.pages.linearDocument#block", 131 + block: { 132 + $type: "pub.leaflet.blocks.header", 133 + level: headingLevel?.data.value || 1, 134 + plaintext: stringValue, 135 + }, 136 + } as PubLeafletPagesLinearDocument.Block, 137 + ]; 138 + } 139 + 140 + if (b.type == "text") { 141 + let stringValue = getBlockContent(b.value); 142 + return [ 143 + { 144 + $type: "pub.leaflet.pages.linearDocument#block", 145 + block: { 146 + $type: ids.PubLeafletBlocksText, 147 + plaintext: stringValue, 148 + }, 149 + } as PubLeafletPagesLinearDocument.Block, 150 + ]; 151 + } 152 + if (b.type == "image") { 153 + let [image] = scan.eav(b.value, "block/image"); 154 + if (!image) return []; 155 + let blobref = imageMap.get(image.data.src); 156 + if (!blobref) return []; 157 + return [ 158 + { 159 + $type: "pub.leaflet.pages.linearDocument#block", 160 + block: { 161 + $type: "pub.leaflet.blocks.image", 162 + image: blobref, 163 + aspectRatio: { 164 + height: image.data.height, 165 + width: image.data.width, 166 + }, 167 + }, 168 + } as PubLeafletPagesLinearDocument.Block, 169 + ]; 170 + } 171 + return []; 172 + }); 173 + } 174 + 175 + function blocksToHtml( 176 + blocks: Block[], 177 + imageMap: Map<string, BlobRef>, 178 + scan: ReturnType<typeof scanIndexLocal>, 179 + publication_uri: string, 180 + ) { 181 + const getBlockContent = (b: string) => { 182 + let [content] = scan.eav(b, "block/text"); 183 + if (!content) return ""; 184 + let doc = new Y.Doc(); 185 + const update = base64.toByteArray(content.data.value); 186 + Y.applyUpdate(doc, update); 187 + let nodes = doc.getXmlElement("prosemirror").toArray(); 188 + let stringValue = YJSFragmentToString(nodes[0]); 189 + return stringValue; 190 + }; 191 + return blocks 192 + .flatMap((b) => { 193 + if (b.type !== "text" && b.type !== "heading" && b.type !== "image") 194 + return []; 195 + if (b.type === "heading") { 196 + let [headingLevel] = scan.eav(b.value, "block/heading-level"); 197 + 198 + let stringValue = getBlockContent(b.value); 199 + let l = headingLevel?.data.value || 1; 200 + return [`<h${l}>${stringValue}</h${l}>`]; 201 + } 202 + 203 + if (b.type == "text") { 204 + let stringValue = getBlockContent(b.value); 205 + return `<p>${stringValue}</p>`; 206 + } 207 + if (b.type == "image") { 208 + let [image] = scan.eav(b.value, "block/image"); 209 + if (!image) return []; 210 + let blobref = imageMap.get(image.data.src); 211 + if (!blobref) return []; 212 + let uri = new AtUri(publication_uri); 213 + return `<img 214 + height=${image.data.height} 215 + width=${image.data.width}> 216 + src="https://bsky.social/xrpc/com.atproto.sync.getBlob?did=${uri.hostname}&cid=${(blobref as unknown as { $link: string })["$link"]}" 217 + </img>`; 218 + } 219 + return [""]; 220 + }) 221 + .join("\n"); 222 + } 223 + 224 + async function sendPostToEmailSubscribers( 225 + publication_uri: string, 226 + post: { content: string; title: string }, 227 + ) { 228 + let { data: publication } = await supabaseServerClient 229 + .from("publications") 230 + .select("*, subscribers_to_publications(*)") 231 + .eq("uri", publication_uri) 232 + .single(); 233 + 234 + let res = await fetch("https://api.postmarkapp.com/email/batch", { 235 + method: "POST", 236 + headers: { 237 + "Content-Type": "application/json", 238 + "X-Postmark-Server-Token": process.env.POSTMARK_API_KEY!, 239 + }, 240 + body: JSON.stringify( 241 + publication?.subscribers_to_publications.map((sub) => ({ 242 + Headers: [ 243 + { 244 + Name: "List-Unsubscribe-Post", 245 + Value: "List-Unsubscribe=One-Click", 246 + }, 247 + { 248 + Name: "List-Unsubscribe", 249 + Value: `<${"TODO"}/mail/unsubscribe?sub_id=${sub.identity}>`, 250 + }, 251 + ], 252 + MessageStream: "broadcast", 253 + From: `${publication.name} <mailbox@leaflet.pub>`, 254 + Subject: post.title, 255 + To: sub.identity, 256 + HtmlBody: ` 257 + <h1>${publication.name}</h1> 258 + <hr style="margin-top: 1em; margin-bottom: 1em;"> 259 + ${post.content} 260 + <hr style="margin-top: 1em; margin-bottom: 1em;"> 261 + This is a super alpha release! Ask Jared if you want to unsubscribe (sorry) 262 + `, 263 + TextBody: post.content, 264 + })), 265 + ), 266 + }); 267 + }
actions/signInWithBluesky.ts

This is a binary file and will not be displayed.

+16
actions/subscribeToPublicationWithEmail.ts
··· 1 + "use server"; 2 + import { supabaseServerClient } from "supabase/serverClient"; 3 + import { getIdentityData } from "./getIdentityData"; 4 + 5 + export async function subscribeToPublicationWithEmail(publication: string) { 6 + let identity = await getIdentityData(); 7 + console.log("yoohooo"); 8 + console.log(identity); 9 + if (!identity || !identity.email) return null; 10 + //This is an email relation!! 11 + console.log( 12 + await supabaseServerClient 13 + .from("subscribers_to_publications") 14 + .insert({ publication: publication, identity: identity.email }), 15 + ); 16 + }
+11 -6
app/[leaflet_id]/page.tsx
··· 12 12 import { getRSVPData } from "actions/getRSVPData"; 13 13 import { PageSWRDataProvider } from "components/PageSWRDataProvider"; 14 14 import { getPollData } from "actions/pollActions"; 15 + import { PublicationContextProvider } from "components/Providers/PublicationContext"; 15 16 16 17 export const preferredRegion = ["sfo1"]; 17 18 export const dynamic = "force-dynamic"; ··· 30 31 let res = await supabase 31 32 .from("permission_tokens") 32 33 .select( 33 - "*, permission_token_rights(*), custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*) ", 34 + "*, permission_token_rights(*), custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*),leaflets_in_publications(publications(*)) ", 34 35 ) 35 36 .eq("id", props.params.leaflet_id) 36 37 .single(); ··· 68 69 leaflet_id={res.data.id} 69 70 domains={res.data.custom_domain_routes} 70 71 > 71 - <Leaflet 72 - initialFacts={initialFacts} 73 - leaflet_id={rootEntity} 74 - token={res.data} 75 - /> 72 + <PublicationContextProvider 73 + publication={res.data.leaflets_in_publications[0]?.publications} 74 + > 75 + <Leaflet 76 + initialFacts={initialFacts} 77 + leaflet_id={rootEntity} 78 + token={res.data} 79 + /> 80 + </PublicationContextProvider> 76 81 </PageSWRDataProvider> 77 82 ); 78 83 }
+41
app/api/oauth/[route]/oauth-metadata.ts
··· 1 + import { OAuthClientMetadata } from "@atproto/oauth-client-node"; 2 + const hostname = 3 + process.env.NODE_ENV === "development" 4 + ? "http://localhost:3000" 5 + : "https://leaflet.pub"; 6 + 7 + const localconfig: OAuthClientMetadata = { 8 + client_id: `http://localhost/?redirect_uri=${encodeURI(`http://127.0.0.1:3000/api/oauth/callback`)}&scope=${encodeURIComponent("atproto transition:generic")}`, 9 + client_name: `Leaflet`, 10 + client_uri: hostname, 11 + redirect_uris: [`http://127.0.0.1:3000/api/oauth/callback`], 12 + grant_types: [`authorization_code`, `refresh_token`], 13 + response_types: [`code`], 14 + application_type: `web`, 15 + scope: "atproto transition:generic", 16 + token_endpoint_auth_method: `none`, 17 + dpop_bound_access_tokens: true, 18 + }; 19 + 20 + const prodconfig: OAuthClientMetadata = { 21 + client_id: `${hostname}/api/oauth/metadata`, 22 + client_name: `Leaflet`, 23 + client_uri: hostname, 24 + logo_uri: `${hostname}/logo.png`, 25 + tos_uri: `${hostname}/tos`, 26 + policy_uri: `${hostname}/policy`, 27 + redirect_uris: 28 + process.env.NODE_ENV === "development" 29 + ? [`http://127.0.0.1:3000/api/oauth/callback`] 30 + : [`https://leaflet.pub/api/oauth/callback`], 31 + grant_types: [`authorization_code`, `refresh_token`], 32 + response_types: [`code`], 33 + application_type: `web`, 34 + scope: "atproto transition:generic", 35 + token_endpoint_auth_method: `private_key_jwt`, 36 + token_endpoint_auth_signing_alg: "ES256", 37 + dpop_bound_access_tokens: true, 38 + jwks_uri: `${hostname}/api/oauth/jwks`, 39 + }; 40 + export const oauth_metadata = 41 + process.env.NODE_ENV === "development" ? localconfig : prodconfig;
+109
app/api/oauth/[route]/route.ts
··· 1 + import { OAuthClientMetadata } from "@atproto/oauth-client-node"; 2 + import { createIdentity } from "actions/createIdentity"; 3 + import { drizzle } from "drizzle-orm/postgres-js"; 4 + import { cookies } from "next/headers"; 5 + import { redirect } from "next/navigation"; 6 + import { NextRequest, NextResponse } from "next/server"; 7 + import postgres from "postgres"; 8 + import { createOauthClient } from "src/atproto-oauth"; 9 + 10 + import { supabaseServerClient } from "supabase/serverClient"; 11 + 12 + type OauthRequestClientState = { 13 + redirect: string | null; 14 + }; 15 + export async function GET( 16 + req: NextRequest, 17 + { params }: { params: { route: string; handle?: string } }, 18 + ) { 19 + let client = await createOauthClient(); 20 + switch (params.route) { 21 + case "metadata": 22 + return NextResponse.json(client.clientMetadata); 23 + case "jwks": 24 + return NextResponse.json(client.jwks); 25 + case "login": { 26 + const searchParams = req.nextUrl.searchParams; 27 + const handle = searchParams.get("handle") as string; 28 + // Put originating page here! 29 + let redirect = searchParams.get("redirect_url"); 30 + let state: OauthRequestClientState = { redirect }; 31 + 32 + // Revoke any pending authentication requests if the connection is closed (optional) 33 + const ac = new AbortController(); 34 + 35 + const url = await client.authorize(handle, { 36 + scope: "atproto transition:generic", 37 + signal: ac.signal, 38 + state: JSON.stringify(state), 39 + // Only supported if OAuth server is openid-compliant 40 + ui_locales: "fr-CA fr en", 41 + }); 42 + 43 + return NextResponse.redirect(url); 44 + } 45 + case "callback": { 46 + const params = new URLSearchParams(req.url.split("?")[1]); 47 + console.log(params); 48 + 49 + let redirectPath = "/lish"; 50 + try { 51 + const { session, state } = await client.callback(params); 52 + let s: OauthRequestClientState = JSON.parse(state || "{}"); 53 + redirectPath = s.redirect || "/lish"; 54 + let { data: identity } = await supabaseServerClient 55 + .from("identities") 56 + .select() 57 + .eq("atp_did", session.did) 58 + .single(); 59 + if (!identity) { 60 + let existingIdentity = cookies().get("auth_token"); 61 + if (existingIdentity) { 62 + let data = await supabaseServerClient 63 + .from("email_auth_tokens") 64 + .select("*, identities(*)") 65 + .single(); 66 + if (data.data?.identity && data.data.confirmed) 67 + await supabaseServerClient 68 + .from("identities") 69 + .update({ atp_did: session.did }) 70 + .eq("id", data.data.identity); 71 + return; 72 + } 73 + const client = postgres(process.env.DB_URL as string, { 74 + idle_timeout: 5, 75 + }); 76 + const db = drizzle(client); 77 + identity = await createIdentity(db, { atp_did: session.did }); 78 + } 79 + let { data: token } = await supabaseServerClient 80 + .from("email_auth_tokens") 81 + .insert({ 82 + identity: identity.id, 83 + confirmed: true, 84 + confirmation_code: "", 85 + }) 86 + .select() 87 + .single(); 88 + 89 + if (token) 90 + cookies().set("auth_token", token.id, { 91 + maxAge: 60 * 60 * 24 * 365, 92 + secure: process.env.NODE_ENV === "production", 93 + httpOnly: true, 94 + sameSite: "lax", 95 + }); 96 + 97 + // Process successful authentication here 98 + console.log("authorize() was called with state:", state); 99 + 100 + console.log("User authenticated as:", session.did); 101 + } catch (e) { 102 + redirect(redirectPath); 103 + } 104 + return redirect(redirectPath); 105 + } 106 + default: 107 + return NextResponse.json({ error: "Invalid route" }, { status: 404 }); 108 + } 109 + }
+8
app/home/AccountSettings.tsx
··· 21 21 } 22 22 > 23 23 <MenuItem 24 + onSelect={() => { 25 + //I guess redirect them to the bluesky oauth endpoint? 26 + }} 27 + > 28 + Link to Bluesky 29 + </MenuItem> 30 + o 31 + <MenuItem 24 32 onSelect={async () => { 25 33 await logout(); 26 34 mutate("identity");
+10
app/lish/AlphaBanner.tsx
··· 1 + import Link from "next/link"; 2 + 3 + export const AlphaBanner = () => { 4 + return ( 5 + <div className="w-full h-fit text-center bg-accent-1 text-accent-2"> 6 + We're still in Early Alpha! <Link href="./lish/">Sign Up</Link> for 7 + Updates :) 8 + </div> 9 + ); 10 + };
+97
app/lish/Footer.tsx
··· 1 + "use client"; 2 + import { MoreOptionsTiny } from "components/Icons"; 3 + import { Menu, MenuItem } from "components/Layout"; 4 + import { useEffect, useState } from "react"; 5 + import { SubscribeButton } from "./Subscribe"; 6 + import Link from "next/link"; 7 + import { ButtonPrimary } from "components/Buttons"; 8 + import { usePublicationRelationship } from "./[handle]/[publication]/usePublicationRelationship"; 9 + import { usePublicationContext } from "components/Providers/PublicationContext"; 10 + 11 + export const Footer = (props: { pageType: "post" | "pub" }) => { 12 + return ( 13 + <div className="footer w-full bg-bg-page border-0 border-t border-border flex flex-col "> 14 + <ScrollProgress /> 15 + <div className="footerContent w-full min-h-12 h-fit max-w-prose mx-auto px-4 py-2 flex justify-between items-center gap-6"> 16 + <MoreOptionsMenu /> 17 + <FooterSubscribeButton pageType={props.pageType} /> 18 + </div> 19 + </div> 20 + ); 21 + }; 22 + 23 + const ScrollProgress = () => { 24 + let [scrollPercent, setScrollPercent] = useState(0); 25 + 26 + useEffect(() => { 27 + let post = document.getElementById("post"); 28 + 29 + let onScroll = () => { 30 + if (!post) return; 31 + let currentScroll = post?.scrollTop; 32 + let totalScroll = post?.scrollHeight - post?.clientHeight; 33 + setScrollPercent((currentScroll / totalScroll) * 100); 34 + }; 35 + post?.addEventListener("scroll", onScroll); 36 + return () => post?.removeEventListener("scroll", onScroll); 37 + }, []); 38 + return ( 39 + <div className="footerScrollProgress w-full h-1 bg-bg-page"> 40 + <div 41 + className={`h-full bg-accent-contrast`} 42 + style={{ width: `${scrollPercent}%` }} 43 + ></div> 44 + </div> 45 + ); 46 + }; 47 + 48 + const FooterSubscribeButton = (props: { pageType: "post" | "pub" }) => { 49 + let [pubHeaderIsVisible, setPubHeaderIsVisible] = useState( 50 + props.pageType === "pub" ? true : false, 51 + ); 52 + let rel = usePublicationRelationship(); 53 + let { publication } = usePublicationContext(); 54 + 55 + useEffect(() => { 56 + let pubHeader = document.getElementById("pub-header"); 57 + if (!pubHeader) return; 58 + let observer = new IntersectionObserver( 59 + (entries) => { 60 + entries.forEach((entry) => { 61 + setPubHeaderIsVisible(entry.isIntersecting); 62 + }); 63 + }, 64 + { threshold: 0 }, 65 + ); 66 + observer.observe(pubHeader); 67 + return () => observer.unobserve(pubHeader); 68 + }, []); 69 + 70 + if (rel?.isSubscribed || pubHeaderIsVisible || !publication) return; 71 + if (rel?.isAuthor) 72 + return ( 73 + <div className="flex gap-2"> 74 + <ButtonPrimary>Write a Draft</ButtonPrimary> 75 + {/* <ShareButton /> */} 76 + </div> 77 + ); 78 + return <SubscribeButton compact publication={publication?.uri} />; 79 + }; 80 + const MoreOptionsMenu = () => { 81 + return ( 82 + <Menu trigger={<MoreOptionsTiny className="footerMoreOptions rotate-90" />}> 83 + <MenuItem onSelect={() => {}}>Log in</MenuItem> 84 + <hr className="border-border-light" /> 85 + 86 + <small className="text-tertiary px-3 leading-none pt-2 font-bold"> 87 + Back to... 88 + </small> 89 + <MenuItem onSelect={() => {}}> 90 + <Link href="./publication">Leaflet Explorers</Link> 91 + </MenuItem> 92 + <MenuItem onSelect={() => {}}> 93 + <Link href="./">Your Feed</Link> 94 + </MenuItem> 95 + </Menu> 96 + ); 97 + };
+214
app/lish/LishHome.tsx
··· 1 + "use client"; 2 + import { ButtonPrimary } from "components/Buttons"; 3 + import Link from "next/link"; 4 + import { useState } from "react"; 5 + import { PostList } from "./PostList"; 6 + 7 + import { Input } from "components/Input"; 8 + import { useIdentityData } from "components/IdentityProvider"; 9 + import { NewDraftButton } from "./[handle]/[publication]/NewDraftButton"; 10 + 11 + export const LishHome = () => { 12 + let [state, setState] = useState<"posts" | "subscriptions">("posts"); 13 + return ( 14 + <div className="w-full h-fit min-h-full p-4 bg-bg-leaflet"> 15 + <div className="flex flex-col gap-6 justify-center place-items-center max-w-prose w-full mx-auto"> 16 + <div 17 + className="p-4 rounded-md w-full" 18 + style={{ 19 + backgroundColor: 20 + "color-mix(in oklab, rgb(var(--accent-contrast)), rgb(var(--bg-page)) 85%)", 21 + }} 22 + > 23 + <MyPublicationList /> 24 + </div> 25 + 26 + {/* <div className="homeFeed w-full flex flex-col"> 27 + <div className="flex gap-1 justify-center pb-2"> 28 + <Tab 29 + name="updates" 30 + active={state === "posts"} 31 + onClick={() => setState("posts")} 32 + /> 33 + <Tab 34 + name="subscriptions" 35 + active={state === "subscriptions"} 36 + onClick={() => setState("subscriptions")} 37 + /> 38 + </div> 39 + <hr className="border-border w-full mb-2" /> 40 + {state === "posts" ? ( 41 + <PostFeed /> 42 + ) : ( 43 + <SubscriptionList publications={Subscriptions} /> 44 + )} 45 + </div> */} 46 + </div> 47 + </div> 48 + ); 49 + }; 50 + 51 + const Tab = (props: { name: string; active: boolean; onClick: () => void }) => { 52 + return ( 53 + <div 54 + className={`border-border px-2 py-1 ${props.active ? "font-bold" : ""}`} 55 + onClick={props.onClick} 56 + > 57 + {props.name} 58 + </div> 59 + ); 60 + }; 61 + 62 + const MyPublicationList = () => { 63 + let { identity } = useIdentityData(); 64 + if (!identity || !identity?.atp_did) { 65 + return ( 66 + <div className="flex flex-col justify-center text-center place-items-center"> 67 + <div className="font-bold text-center"> 68 + Connect to Bluesky <br className="sm:hidden" /> 69 + to start publishing! 70 + </div> 71 + <small className="text-secondary text-center pt-1"> 72 + We use the ATProtocol to store all your publication data on the open 73 + web. That means we cannot lock you into our platform, you will ALWAYS 74 + be free to easily move elsewhere. <a>Learn More.</a> 75 + </small> 76 + <form 77 + action="/api/oauth/login?redirect_url=/lish" 78 + method="GET" 79 + className="relative w-fit mt-4 " 80 + > 81 + <Input 82 + type="text" 83 + className="input-with-border !pr-[88px] !py-1 grow w-full" 84 + name="handle" 85 + placeholder="Enter Bluesky handle..." 86 + required 87 + /> 88 + <ButtonPrimary 89 + compact 90 + className="absolute right-1 top-1 !outline-0" 91 + type="submit" 92 + > 93 + Connect 94 + </ButtonPrimary> 95 + </form> 96 + </div> 97 + ); 98 + } 99 + if (Publications.length === 0) { 100 + return ( 101 + <div> 102 + <Link href={"./lish/createPub"}> 103 + <ButtonPrimary>Start a Publication!</ButtonPrimary> 104 + </Link> 105 + </div> 106 + ); 107 + } 108 + return ( 109 + <div className="w-full flex flex-col gap-2"> 110 + <PublicationList publications={identity.publications} /> 111 + <Link 112 + href={"./lish/createPub"} 113 + className="text-sm place-self-start text-tertiary hover:text-accent-contrast" 114 + > 115 + New Publication 116 + </Link> 117 + </div> 118 + ); 119 + }; 120 + 121 + const PublicationList = (props: { 122 + publications: { 123 + identity_did: string; 124 + indexed_at: string; 125 + name: string; 126 + uri: string; 127 + }[]; 128 + }) => { 129 + let { identity } = useIdentityData(); 130 + 131 + return ( 132 + <div className="w-full flex flex-col gap-2"> 133 + {props.publications?.map((d) => ( 134 + <div 135 + key={d.uri} 136 + className={`pubPostListItem flex hover:no-underline justify-between items-center`} 137 + > 138 + <Link 139 + className="justify-self-start font-bold hover:no-underline" 140 + href={`/lish/${identity?.resolved_did?.alsoKnownAs?.[0].slice(5)}/${d.name}/`} 141 + > 142 + <div key={d.uri}>{d.name}</div> 143 + </Link> 144 + <NewDraftButton publication={d.uri} /> 145 + </div> 146 + ))} 147 + </div> 148 + ); 149 + }; 150 + 151 + const SubscriptionList = (props: { 152 + publications: { title: string; description: string }[]; 153 + }) => { 154 + if (props.publications.length === 0) 155 + return ( 156 + <div className="w-full text-center text-tertiary italic pt-4"> 157 + No subscriptions yet! 158 + </div> 159 + ); 160 + return ( 161 + <div className="w-full flex flex-col gap-2"> 162 + {props.publications.map((pub) => { 163 + return <SubscriptionListItem {...pub} />; 164 + })} 165 + </div> 166 + ); 167 + }; 168 + 169 + const SubscriptionListItem = (props: { 170 + title: string; 171 + description: string; 172 + }) => { 173 + return ( 174 + <Link 175 + href="./lish/publication" 176 + className={`pubPostListItem flex flex-col hover:no-underline justify-between items-center`} 177 + > 178 + <h4 className="justify-self-start">{props.title}</h4> 179 + 180 + <div className="text-secondary text-sm pt-1">{props.description}</div> 181 + <hr className="border-border-light mt-3" /> 182 + </Link> 183 + ); 184 + }; 185 + 186 + const PostFeed = () => { 187 + return <PostList isFeed posts={[]} />; 188 + }; 189 + 190 + let Subscriptions = [ 191 + { 192 + title: "vrk loves paper", 193 + description: 194 + "Exploring software that loves paper as much as I do. I'll be documenting my learnings, loves, confusions and creations in this newsletter!", 195 + }, 196 + { 197 + title: "rhrizome r&d", 198 + description: 199 + "Design, research, and complexity. A field guide for novel problems.", 200 + }, 201 + { 202 + title: "Dead Languages Society ", 203 + description: 204 + "A guided tour through the history of English and its relatives.", 205 + }, 206 + ]; 207 + 208 + let Publications = [ 209 + { 210 + title: "Leaflet Explorers", 211 + description: 212 + "We're making Leaflet, a fast fun web app for making delightful documents. Sign up to follow along as we build Leaflet! We send updates every week or two", 213 + }, 214 + ];
+86
app/lish/PostList.tsx
··· 1 + "use client"; 2 + import Link from "next/link"; 3 + import { Separator } from "components/Layout"; 4 + import { Json } from "supabase/database.types"; 5 + import { PubLeafletDocument } from "lexicons/src"; 6 + import { ButtonPrimary } from "components/Buttons"; 7 + import { useIdentityData } from "components/IdentityProvider"; 8 + import { usePublicationRelationship } from "./[handle]/[publication]/usePublicationRelationship"; 9 + import { useParams } from "next/navigation"; 10 + import { AtUri } from "@atproto/syntax"; 11 + 12 + export const PostList = (props: { 13 + isFeed?: boolean; 14 + posts: { 15 + documents: { 16 + data: Json; 17 + indexed_at: string; 18 + uri: string; 19 + } | null; 20 + }[]; 21 + }) => { 22 + if (props.posts.length === 0) { 23 + if (props.isFeed) { 24 + return ( 25 + <div className="italic text-tertiary w-full text-center pt-4"> 26 + Subscribe to publications to see posts in your feed 27 + </div> 28 + ); 29 + } 30 + return ( 31 + <div className="italic text-tertiary flex flex-col gap-2 justify-center place-items-center"> 32 + <div>Welcome to your new Publication</div> 33 + <ButtonPrimary>Start Drafting!</ButtonPrimary> 34 + </div> 35 + ); 36 + } 37 + 38 + return ( 39 + <div className="pubPostList flex flex-col gap-3"> 40 + {props.posts.map((post, index) => { 41 + let p = post.documents?.data as PubLeafletDocument.Record; 42 + let uri = new AtUri(post.documents?.uri!); 43 + 44 + return ( 45 + <PostListItem {...p} key={index} isFeed={props.isFeed} uri={uri} /> 46 + ); 47 + })} 48 + </div> 49 + ); 50 + }; 51 + 52 + const PostListItem = ( 53 + props: { 54 + isFeed?: boolean; 55 + uri: AtUri; 56 + } & PubLeafletDocument.Record, 57 + ) => { 58 + let { identity } = useIdentityData(); 59 + let params = useParams(); 60 + return ( 61 + <div className="pubPostListItem flex flex-col"> 62 + {props.isFeed && ( 63 + <Link 64 + href={`/lish/${identity?.resolved_did?.alsoKnownAs?.[0].slice(5)}/${props.publication}/`} 65 + className="font-bold text-tertiary hover:no-underline text-sm " 66 + > 67 + {props.publication} 68 + </Link> 69 + )} 70 + 71 + <Link 72 + href={`/lish/${identity?.resolved_did?.alsoKnownAs?.[0].slice(5)}/${params.publication}/${props.uri.rkey}/`} 73 + className="pubPostListContent flex flex-col hover:no-underline hover:text-accent-contrast" 74 + > 75 + <h4>{props.title}</h4> 76 + {/* <div className="text-secondary text-sm pt-1">placeholder description</div> */} 77 + <div className="flex gap-2 text-sm text-tertiary"> 78 + {/* <div className="">{props.publishedAt}</div> */} 79 + {/* <Separator classname="h-4" /> */} 80 + <div>by {identity?.resolved_did?.alsoKnownAs?.[0].slice(5)}</div> 81 + </div> 82 + <hr className="border-border-light mt-3" /> 83 + </Link> 84 + </div> 85 + ); 86 + };
+167
app/lish/Subscribe.tsx
··· 1 + "use client"; 2 + import { ButtonPrimary } from "components/Buttons"; 3 + import { ArrowRightTiny, ShareSmall } from "components/Icons"; 4 + import { useEffect, useState } from "react"; 5 + import { Input } from "components/Input"; 6 + import { useIdentityData } from "components/IdentityProvider"; 7 + import { SecondaryAuthTokenContextImpl } from "twilio/lib/rest/accounts/v1/secondaryAuthToken"; 8 + import { 9 + confirmEmailAuthToken, 10 + requestAuthEmailToken, 11 + } from "actions/emailAuth"; 12 + import { subscribeToPublicationWithEmail } from "actions/subscribeToPublicationWithEmail"; 13 + 14 + type State = 15 + | { state: "email" } 16 + | { state: "code"; token: string } 17 + | { state: "success" }; 18 + export const SubscribeButton = (props: { 19 + compact?: boolean; 20 + publication: string; 21 + }) => { 22 + let { identity, mutate } = useIdentityData(); 23 + let [emailInputValue, setEmailInputValue] = useState(""); 24 + let [codeInputValue, setCodeInputValue] = useState(""); 25 + let [state, setState] = useState<State>({ state: "email" }); 26 + 27 + if (state.state === "email") { 28 + return ( 29 + <div className="flex gap-2"> 30 + <div className="flex relative w-full max-w-sm"> 31 + <Input 32 + type="email" 33 + className="input-with-border !pr-[104px] !py-1 grow w-full" 34 + placeholder={ 35 + props.compact ? "subscribe with email..." : "email here..." 36 + } 37 + disabled={!!identity?.email} 38 + value={identity?.email ? identity.email : emailInputValue} 39 + onChange={(e) => { 40 + setEmailInputValue(e.currentTarget.value); 41 + }} 42 + /> 43 + <ButtonPrimary 44 + compact 45 + className="absolute right-1 top-1 !outline-0" 46 + onClick={async () => { 47 + if (identity?.email) { 48 + await subscribeToPublicationWithEmail(props.publication); 49 + //optimistically could add! 50 + await mutate(); 51 + return; 52 + } 53 + let tokenID = await requestAuthEmailToken(emailInputValue); 54 + setState({ state: "code", token: tokenID }); 55 + }} 56 + > 57 + {props.compact ? ( 58 + <ArrowRightTiny className="w-4 h-6" /> 59 + ) : ( 60 + "Subscribe" 61 + )} 62 + </ButtonPrimary> 63 + </div> 64 + {/* <ShareButton /> */} 65 + </div> 66 + ); 67 + } 68 + if (state.state === "code") { 69 + return ( 70 + <div 71 + className="w-full flex flex-col justify-center place-items-center p-4 rounded-md" 72 + style={{ 73 + background: 74 + "color-mix(in oklab, rgb(var(--accent-contrast)), rgb(var(--bg-page)) 85%)", 75 + }} 76 + > 77 + <div className="flex flex-col leading-snug text-secondary"> 78 + <div>Please enter the code we sent to </div> 79 + <div className="italic font-bold">{emailInputValue}</div> 80 + </div> 81 + 82 + <ConfirmCodeInput 83 + publication={props.publication} 84 + token={state.token} 85 + codeInputValue={codeInputValue} 86 + setCodeInputValue={setCodeInputValue} 87 + setState={setState} 88 + /> 89 + 90 + <button 91 + className="text-accent-contrast text-sm mt-1" 92 + onClick={() => { 93 + setState({ state: "email" }); 94 + }} 95 + > 96 + Re-enter Email 97 + </button> 98 + </div> 99 + ); 100 + } 101 + 102 + if (state.state === "success") { 103 + return ( 104 + <div 105 + className={`w-full flex flex-col gap-2 justify-center place-items-center p-4 rounded-md text-secondary ${props.compact ? "py-1 animate-bounce" : "p-4"}`} 106 + style={{ 107 + background: 108 + "color-mix(in oklab, rgb(var(--accent-contrast)), rgb(var(--bg-page)) 85%)", 109 + }} 110 + > 111 + <div className="flex gap-2 leading-snug font-bold italic"> 112 + <div>You're subscribed!</div> 113 + {/* <ShareButton /> */} 114 + </div> 115 + </div> 116 + ); 117 + } 118 + }; 119 + 120 + export const ShareButton = () => { 121 + return ( 122 + <button className="text-accent-contrast"> 123 + <ShareSmall /> 124 + </button> 125 + ); 126 + }; 127 + 128 + const ConfirmCodeInput = (props: { 129 + codeInputValue: string; 130 + token: string; 131 + setCodeInputValue: (value: string) => void; 132 + setState: (state: State) => void; 133 + publication: string; 134 + }) => { 135 + let { mutate } = useIdentityData(); 136 + return ( 137 + <div className="relative w-fit mt-2"> 138 + <Input 139 + type="text" 140 + pattern="[0-9]" 141 + className="input-with-border !pr-[88px] !py-1 max-w-[156px]" 142 + placeholder="000000" 143 + value={props.codeInputValue} 144 + onChange={(e) => { 145 + props.setCodeInputValue(e.currentTarget.value); 146 + }} 147 + /> 148 + <ButtonPrimary 149 + compact 150 + className="absolute right-1 top-1 !outline-0" 151 + onClick={async () => { 152 + console.log( 153 + await confirmEmailAuthToken(props.token, props.codeInputValue), 154 + ); 155 + 156 + await subscribeToPublicationWithEmail(props.publication); 157 + //optimistically could add! 158 + await mutate(); 159 + props.setState({ state: "success" }); 160 + return; 161 + }} 162 + > 163 + Confirm 164 + </ButtonPrimary> 165 + </div> 166 + ); 167 + };
+31
app/lish/[handle]/[publication]/CallToActionButton.tsx
··· 1 + "use client"; 2 + 3 + import { SubscribeButton } from "app/lish/Subscribe"; 4 + import { usePublicationRelationship } from "./usePublicationRelationship"; 5 + import { usePublicationContext } from "components/Providers/PublicationContext"; 6 + import { NewDraftButton } from "./NewDraftButton"; 7 + import { Menu, MenuItem } from "components/Layout"; 8 + import { ArrowRightTiny, MoreOptionsTiny, ShareSmall } from "components/Icons"; 9 + 10 + export function CallToActionButton() { 11 + let rel = usePublicationRelationship(); 12 + let { publication } = usePublicationContext(); 13 + if (!publication) return null; 14 + if (rel?.isAuthor) return <NewDraftButton publication={publication.uri} />; 15 + if (rel?.isSubscribed) 16 + return ( 17 + <div className="flex gap-2"> 18 + <div className="font-bold">You're Subscribed!</div> 19 + <ManageSubscriptionMenu /> 20 + </div> 21 + ); 22 + return <SubscribeButton publication={publication.uri} />; 23 + } 24 + 25 + const ManageSubscriptionMenu = () => { 26 + return ( 27 + <Menu trigger={<MoreOptionsTiny className="rotate-90" />}> 28 + <MenuItem onSelect={() => {}}>Unsub!</MenuItem> 29 + </Menu> 30 + ); 31 + };
+20
app/lish/[handle]/[publication]/NewDraftButton.tsx
··· 1 + "use client"; 2 + import { createPublicationDraft } from "actions/createPublicationDraft"; 3 + import { ButtonPrimary } from "components/Buttons"; 4 + import { useRouter } from "next/navigation"; 5 + 6 + export function NewDraftButton(props: { publication: string }) { 7 + let router = useRouter(); 8 + return ( 9 + <div className="flex gap-2"> 10 + <ButtonPrimary 11 + onClick={async () => { 12 + let newLeaflet = await createPublicationDraft(props.publication); 13 + router.push(`/${newLeaflet}`); 14 + }} 15 + > 16 + New Draft 17 + </ButtonPrimary> 18 + </div> 19 + ); 20 + }
+85
app/lish/[handle]/[publication]/[rkey]/page.tsx
··· 1 + import Link from "next/link"; 2 + import { Footer } from "../../../Footer"; 3 + import { getPds, IdResolver } from "@atproto/identity"; 4 + import { supabaseServerClient } from "supabase/serverClient"; 5 + import { AtUri } from "@atproto/syntax"; 6 + import { ids } from "lexicons/src/lexicons"; 7 + import { 8 + PubLeafletBlocksHeader, 9 + PubLeafletBlocksImage, 10 + PubLeafletBlocksText, 11 + PubLeafletDocument, 12 + PubLeafletPagesLinearDocument, 13 + } from "lexicons/src"; 14 + 15 + const idResolver = new IdResolver(); 16 + export default async function Post(props: { 17 + params: { publication: string; handle: string; rkey: string }; 18 + }) { 19 + let did = await idResolver.handle.resolve(props.params.handle); 20 + if (!did) return <div> can't resolve handle</div>; 21 + let { data: document } = await supabaseServerClient 22 + .from("documents") 23 + .select("*") 24 + .eq("uri", AtUri.make(did, ids.PubLeafletDocument, props.params.rkey)) 25 + .single(); 26 + if (!document?.data) return <div>notfound</div>; 27 + let record = document.data as PubLeafletDocument.Record; 28 + let firstPage = record.pages[0]; 29 + let blocks: PubLeafletPagesLinearDocument.Block[] = []; 30 + if (PubLeafletPagesLinearDocument.isMain(firstPage)) { 31 + blocks = firstPage.blocks || []; 32 + } 33 + return ( 34 + <div className="postPage w-full h-screen bg-bg-leaflet flex items-stretch"> 35 + <div className="pubWrapper flex flex-col w-full "> 36 + <div className="pubContent flex flex-col px-4 py-6 mx-auto max-w-prose h-full w-full overflow-auto"> 37 + <Link 38 + className="font-bold hover:no-underline text-accent-contrast -mb-2 sm:-mb-3" 39 + href={`/lish/${props.params.handle}/${props.params.publication}`} 40 + > 41 + {decodeURIComponent(props.params.publication)} 42 + </Link> 43 + {/* <h1>{record.title}</h1> */} 44 + {blocks.map((b) => { 45 + switch (true) { 46 + case PubLeafletBlocksImage.isMain(b.block): { 47 + return ( 48 + <img 49 + height={b.block.aspectRatio?.height} 50 + width={b.block.aspectRatio?.width} 51 + className="pb-2 sm:pb-3" 52 + src={`https://bsky.social/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${(b.block.image.ref as unknown as { $link: string })["$link"]}`} 53 + /> 54 + ); 55 + } 56 + case PubLeafletBlocksText.isMain(b.block): 57 + return <p className="pt-0 pb-2 sm:pb-3">{b.block.plaintext}</p>; 58 + case PubLeafletBlocksHeader.isMain(b.block): { 59 + if (b.block.level === 1) 60 + return ( 61 + <h1 className="pb-0 pt-2 sm:pt-3">{b.block.plaintext}</h1> 62 + ); 63 + if (b.block.level === 2) 64 + return ( 65 + <h3 className="pb-0 pt-2 sm:pt-3">{b.block.plaintext}</h3> 66 + ); 67 + if (b.block.level === 3) 68 + return ( 69 + <h4 className="pb-0 pt-2 sm:pt-3">{b.block.plaintext}</h4> 70 + ); 71 + // if (b.block.level === 4) return <h4>{b.block.plaintext}</h4>; 72 + // if (b.block.level === 5) return <h5>{b.block.plaintext}</h5>; 73 + return <h6>{b.block.plaintext}</h6>; 74 + } 75 + default: 76 + return null; 77 + } 78 + })} 79 + </div> 80 + 81 + <Footer pageType="post" /> 82 + </div> 83 + </div> 84 + ); 85 + }
+30
app/lish/[handle]/[publication]/layout.tsx
··· 1 + import { IdResolver } from "@atproto/identity"; 2 + import { PublicationContextProvider } from "components/Providers/PublicationContext"; 3 + import { supabaseServerClient } from "supabase/serverClient"; 4 + 5 + const idResolver = new IdResolver(); 6 + export default async function PublicationLayout(props: { 7 + children: React.ReactNode; 8 + params: { 9 + publication: string; 10 + handle: string; 11 + }; 12 + }) { 13 + let did = await idResolver.handle.resolve(props.params.handle); 14 + if (!did) return <>{props.children}</>; 15 + let { data: publication } = await supabaseServerClient 16 + .from("publications") 17 + .select( 18 + "*, documents_in_publications(documents(*)), leaflets_in_publications(*, permission_tokens(*, permission_token_rights(*), custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*) ))", 19 + ) 20 + .eq("identity_did", did) 21 + .eq("name", decodeURIComponent(props.params.publication)) 22 + .single(); 23 + 24 + if (!publication) return <>{props.children}</>; 25 + return ( 26 + <PublicationContextProvider publication={publication}> 27 + {props.children} 28 + </PublicationContextProvider> 29 + ); 30 + }
+75
app/lish/[handle]/[publication]/page.tsx
··· 1 + import { Footer } from "../../Footer"; 2 + import { PostList } from "../../PostList"; 3 + import { getPds, IdResolver } from "@atproto/identity"; 4 + import { supabaseServerClient } from "supabase/serverClient"; 5 + import { AtUri } from "@atproto/syntax"; 6 + import { 7 + AtpBaseClient, 8 + PubLeafletDocument, 9 + PubLeafletPublication, 10 + } from "lexicons/src"; 11 + import { CallToActionButton } from "./CallToActionButton"; 12 + 13 + const idResolver = new IdResolver(); 14 + 15 + export default async function Publication(props: { 16 + params: { publication: string; handle: string }; 17 + }) { 18 + let did = await idResolver.handle.resolve(props.params.handle); 19 + if (!did) return <PubNotFound />; 20 + 21 + let { data: publication } = await supabaseServerClient 22 + .from("publications") 23 + .select( 24 + "*, documents_in_publications(documents(*)), leaflets_in_publications(*, permission_tokens(*, permission_token_rights(*), custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*) ))", 25 + ) 26 + .eq("identity_did", did) 27 + .eq("name", decodeURIComponent(props.params.publication)) 28 + .single(); 29 + if (!publication) return <PubNotFound />; 30 + 31 + let repo = await idResolver.did.resolve(did); 32 + if (!repo) return <PubNotFound />; 33 + const pds = getPds(repo); 34 + let agent = new AtpBaseClient((url, init) => { 35 + return fetch(new URL(url, pds), init); 36 + }); 37 + 38 + try { 39 + let uri = new AtUri(publication.uri); 40 + let publication_record = await agent.pub.leaflet.publication.get({ 41 + repo: props.params.handle, 42 + rkey: uri.rkey, 43 + }); 44 + if (!PubLeafletPublication.isRecord(publication_record.value)) { 45 + return <pre>not a publication?</pre>; 46 + } 47 + 48 + return ( 49 + <div className="pubPage w-full h-screen bg-bg-leaflet flex items-stretch"> 50 + <div className="pubWrapper flex flex-col w-full "> 51 + <div className="pubContent flex flex-col gap-8 px-4 py-6 mx-auto max-w-prose h-full w-full overflow-auto"> 52 + <div 53 + id="pub-header" 54 + className="pubHeader flex flex-col gap-6 justify-center text-center" 55 + > 56 + <div className="flex flex-col gap-1 w-full place-items-center"> 57 + <h2>{publication.name}</h2> 58 + <CallToActionButton /> 59 + </div> 60 + </div> 61 + <PostList posts={publication.documents_in_publications} /> 62 + </div> 63 + <Footer pageType="pub" /> 64 + </div> 65 + </div> 66 + ); 67 + } catch (e) { 68 + console.log(e); 69 + return <pre>{JSON.stringify(e, undefined, 2)}</pre>; 70 + } 71 + } 72 + 73 + const PubNotFound = () => { 74 + return <div>ain't no pub here</div>; 75 + };
+16
app/lish/[handle]/[publication]/usePublicationRelationship.ts
··· 1 + import { AtUri } from "@atproto/syntax"; 2 + import { useIdentityData } from "components/IdentityProvider"; 3 + import { usePublicationContext } from "components/Providers/PublicationContext"; 4 + 5 + export const usePublicationRelationship = () => { 6 + let identity = useIdentityData(); 7 + let publication = usePublicationContext(); 8 + if (!publication.publication) return null; 9 + let pubUri = new AtUri(publication.publication.uri); 10 + let isAuthor = 11 + identity.identity?.atp_did && pubUri.hostname === identity.identity.atp_did; 12 + let isSubscribed = identity.identity?.subscribers_to_publications.find( 13 + (p) => p.publication === publication.publication?.uri, 14 + ); 15 + return { isAuthor, isSubscribed }; 16 + };
+61
app/lish/createPub/CreatePubForm.tsx
··· 1 + "use client"; 2 + import { createPublication } from "actions/createPublication"; 3 + import { ButtonPrimary } from "components/Buttons"; 4 + import { useIdentityData } from "components/IdentityProvider"; 5 + import { InputWithLabel } from "components/Input"; 6 + import Link from "next/link"; 7 + import { useParams, useRouter } from "next/navigation"; 8 + import { useState } from "react"; 9 + 10 + export const CreatePubForm = () => { 11 + let [nameValue, setNameValue] = useState(""); 12 + let [descriptionValue, setDescriptionValue] = useState(""); 13 + 14 + let router = useRouter(); 15 + let { identity } = useIdentityData(); 16 + return ( 17 + <form 18 + className="createPubForm w-full flex flex-col gap-3 bg-bg-page rounded-lg p-3 border border-border-light" 19 + onSubmit={async (e) => { 20 + e.preventDefault(); 21 + await createPublication(nameValue); 22 + router.push( 23 + `/lish/${identity?.resolved_did?.alsoKnownAs?.[0].slice(5)}/${nameValue}/`, 24 + ); 25 + }} 26 + > 27 + <InputWithLabel 28 + type="text" 29 + id="pubName" 30 + label="Name" 31 + value={nameValue} 32 + onChange={(e) => { 33 + setNameValue(e.currentTarget.value); 34 + }} 35 + /> 36 + 37 + {/* <InputWithLabel 38 + label="Description" 39 + textarea 40 + rows={3} 41 + id="pubDescription" 42 + value={descriptionValue} 43 + onChange={(e) => { 44 + setDescriptionValue(e.currentTarget.value); 45 + }} 46 + /> */} 47 + 48 + <div className="flex justify-between items-center"> 49 + <Link 50 + className="hover:no-underline font-bold text-accent-contrast" 51 + href="./" 52 + > 53 + Nevermind 54 + </Link> 55 + <ButtonPrimary className="place-self-end" type="submit"> 56 + Create! 57 + </ButtonPrimary> 58 + </div> 59 + </form> 60 + ); 61 + };
+17
app/lish/createPub/page.tsx
··· 1 + import { CreatePubForm } from "./CreatePubForm"; 2 + import { createClient } from "@supabase/supabase-js"; 3 + import { Database } from "supabase/database.types"; 4 + import { IdResolver } from "@atproto/identity"; 5 + 6 + export default function CreatePub() { 7 + return ( 8 + <div className="createPubPage relative w-full h-screen flex items-stretch bg-bg-leaflet p-4"> 9 + <div className="createPubContent h-full flex items-center max-w-sm w-full mx-auto "> 10 + <div className="createPubFormWrapper h-fit w-full flex flex-col gap-4"> 11 + <h2 className="text-center">Create a New Publication</h2> 12 + <CreatePubForm /> 13 + </div> 14 + </div> 15 + </div> 16 + ); 17 + }
+13
app/lish/page.tsx
··· 1 + import { LishHome } from "./LishHome"; 2 + import { createClient } from "@supabase/supabase-js"; 3 + import { Database } from "supabase/database.types"; 4 + import { AtpBaseClient, PubLeafletPagesLinearDocument } from "lexicons/src"; 5 + import { CredentialSession } from "@atproto/api"; 6 + import { createOauthClient } from "src/atproto-oauth"; 7 + import { getIdentityData } from "actions/getIdentityData"; 8 + import Link from "next/link"; 9 + import { IdResolver } from "@atproto/identity"; 10 + 11 + export default function Lish() { 12 + return <LishHome />; 13 + }
+125
appview/index.ts
··· 1 + import { createClient } from "@supabase/supabase-js"; 2 + import { Database, Json } from "supabase/database.types"; 3 + import { IdResolver } from "@atproto/identity"; 4 + const idResolver = new IdResolver(); 5 + import { Firehose, MemoryRunner } from "@atproto/sync"; 6 + import { ids } from "lexicons/src/lexicons"; 7 + import { 8 + PubLeafletDocument, 9 + PubLeafletPost, 10 + PubLeafletPublication, 11 + } from "lexicons/src"; 12 + import { AtUri } from "@atproto/syntax"; 13 + import { writeFile, readFile } from "fs/promises"; 14 + 15 + const cursorFile = "./cursor"; 16 + 17 + let supabase = createClient<Database>( 18 + process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, 19 + process.env.SUPABASE_SERVICE_ROLE_KEY as string, 20 + ); 21 + async function main() { 22 + let startCursor; 23 + try { 24 + startCursor = parseInt((await readFile(cursorFile)).toString()); 25 + } catch (e) {} 26 + const runner = new MemoryRunner({ 27 + startCursor, 28 + setCursor: async (cursor) => { 29 + await writeFile(cursorFile, cursor.toString()); 30 + // persist cursor 31 + }, 32 + }); 33 + let firehose = new Firehose({ 34 + excludeAccount: true, 35 + excludeIdentity: true, 36 + runner, 37 + idResolver, 38 + filterCollections: [ 39 + ids.PubLeafletDocument, 40 + ids.PubLeafletPublication, 41 + ids.PubLeafletPost, 42 + ], 43 + handleEvent: async (evt) => { 44 + if ( 45 + evt.event == "account" || 46 + evt.event === "identity" || 47 + evt.event === "sync" 48 + ) 49 + return; 50 + if (evt.collection === ids.PubLeafletDocument) { 51 + if (evt.event === "create" || evt.event === "update") { 52 + let record = PubLeafletDocument.validateRecord(evt.record); 53 + if (!record.success) { 54 + console.log(record.error); 55 + return; 56 + } 57 + await supabase.from("documents").upsert({ 58 + uri: evt.uri.toString(), 59 + data: record.value as Json, 60 + }); 61 + let publicationURI = new AtUri(record.value.publication); 62 + 63 + if (publicationURI.host !== evt.uri.host) { 64 + console.log("Unauthorized to create post!"); 65 + return; 66 + } 67 + console.log( 68 + await supabase.from("documents_in_publications").insert({ 69 + publication: record.value.publication, 70 + document: evt.uri.toString(), 71 + }), 72 + ); 73 + } 74 + } 75 + if (evt.collection === ids.PubLeafletPublication) { 76 + if (evt.event === "create" || evt.event === "update") { 77 + let record = PubLeafletPublication.validateRecord(evt.record); 78 + if (!record.success) return; 79 + console.log( 80 + await supabase.from("publications").upsert({ 81 + uri: evt.uri.toString(), 82 + identity_did: evt.did, 83 + name: record.value.name, 84 + }), 85 + ); 86 + } 87 + if (evt.event === "delete") { 88 + console.log("deleting ", evt.rkey); 89 + console.log( 90 + await supabase 91 + .from("publications") 92 + .delete() 93 + .eq("uri", evt.uri.toString()), 94 + ); 95 + } 96 + } 97 + if (evt.collection === ids.PubLeafletPost) { 98 + if (evt.event === "create" || evt.event === "update") { 99 + let record = PubLeafletPost.validateRecord(evt.record); 100 + if (!record.success) return; 101 + } 102 + } 103 + }, 104 + onError: (err) => { 105 + console.error(err); 106 + }, 107 + }); 108 + console.log("starting firehose consumer"); 109 + firehose.start(); 110 + const cleanup = () => { 111 + console.log("shutting down firehose..."); 112 + firehose.destroy(); 113 + runner.destroy(); 114 + process.exit(); 115 + }; 116 + 117 + process.on("SIGINT", cleanup); 118 + process.on("SIGTERM", cleanup); 119 + } 120 + 121 + main(); 122 + 123 + //Should I make a helper for writing these hmmm... I need to make create / updates for all of these 124 + // Creates should basically be the same as updates right? Ya, as long as you make sure to upsert stuff! 125 + //
+2 -2
components/Blocks/RSVPBlock/ContactDetailsForm.tsx
··· 9 9 import { countryCodes } from "src/constants/countryCodes"; 10 10 import { Checkbox } from "components/Checkbox"; 11 11 import { ButtonPrimary, ButtonTertiary } from "components/Buttons"; 12 - import { InputWithLabel, Separator } from "components/Layout"; 12 + import { Separator } from "components/Layout"; 13 13 import { createPhoneAuthToken } from "actions/phone_auth/request_phone_auth_token"; 14 - import { Input } from "components/Input"; 14 + import { Input, InputWithLabel } from "components/Input"; 15 15 import { IPLocationContext } from "components/Providers/IPLocationProvider"; 16 16 import { Popover } from "components/Popover"; 17 17 import { InfoSmall } from "components/Icons";
+13 -14
components/Input.tsx
··· 1 + "use client"; 1 2 import { isIOS } from "@react-aria/utils"; 2 3 import { useCallback, useEffect, useRef } from "react"; 3 4 import { onMouseDown } from "src/utils/iosInputMouseDown"; ··· 63 64 export const InputWithLabel = ( 64 65 props: { 65 66 label: string; 66 - } & JSX.IntrinsicElements["input"], 67 + textarea?: boolean; 68 + } & JSX.IntrinsicElements["input"] & 69 + JSX.IntrinsicElements["textarea"], 67 70 ) => { 68 71 let { label, ...inputProps } = props; 72 + let style = `appearance-none w-full font-normal bg-transparent text-base text-primary focus:outline-0 ${props.className}`; 69 73 return ( 70 - <div> 71 - <div className="input-with-border flex flex-col"> 72 - <label> 73 - <div className="text-sm text-tertiary font-bold italic leading-none pt-0.5"> 74 - {props.label} 75 - </div> 76 - <Input 77 - {...inputProps} 78 - className={`appearance-none w-full font-normal bg-transparent text-base text-primary focus:outline-0 ${props.className}`} 79 - /> 80 - </label> 81 - </div> 82 - </div> 74 + <label className=" input-with-border flex flex-col text-sm text-tertiary font-bold italic leading-tight !py-1 !px-[6px]"> 75 + {props.label} 76 + {props.textarea ? ( 77 + <textarea {...inputProps} className={style} /> 78 + ) : ( 79 + <Input {...inputProps} className={style} /> 80 + )} 81 + </label> 83 82 ); 84 83 };
-17
components/Layout.tsx
··· 86 86 ); 87 87 }; 88 88 89 - export const InputWithLabel = ( 90 - props: { 91 - label: string; 92 - } & JSX.IntrinsicElements["input"], 93 - ) => { 94 - let { label, ...inputProps } = props; 95 - return ( 96 - <label className="text-xs text-tertiary font-bold italic input-with-border flex flex-col w-full"> 97 - {props.label} 98 - <Input 99 - {...inputProps} 100 - className={`appearance-none w-full font-normal bg-transparent text-base text-primary focus:outline-0 ${props.className}`} 101 - /> 102 - </label> 103 - ); 104 - }; 105 - 106 89 export const ShortcutKey = (props: { children: React.ReactNode }) => { 107 90 return ( 108 91 <span>
+2
components/MobileFooter.tsx
··· 8 8 import { useEntitySetContext } from "./EntitySetProvider"; 9 9 import { HelpPopover } from "./HelpPopover"; 10 10 import { Watermark } from "./Watermark"; 11 + import { PublishToPublication } from "./ShareOptions/PublicationOptions"; 11 12 12 13 export function MobileFooter(props: { entityID: string }) { 13 14 let focusedBlock = useUIState((s) => s.focusedEntity); ··· 38 39 <HelpPopover /> 39 40 <ThemePopover entityID={props.entityID} /> 40 41 <ShareOptions /> 42 + <PublishToPublication /> 41 43 </div> 42 44 </div> 43 45 ) : (
+15 -2
components/Pages/index.tsx
··· 44 44 import { LoginButton } from "components/LoginButton"; 45 45 import { useUndoState } from "src/undoManager"; 46 46 import { useIsMobile } from "src/hooks/isMobile"; 47 + import { PublishToPublication } from "components/ShareOptions/PublicationOptions"; 48 + import { ButtonPrimary } from "components/Buttons"; 49 + import { Popover } from "components/Popover"; 50 + import { InputWithLabel } from "components/Input"; 51 + import { usePublicationContext } from "components/Providers/PublicationContext"; 47 52 48 53 export function Pages(props: { rootPage: string }) { 49 54 let rootPage = useEntity(props.rootPage, "root/page")[0]; ··· 52 57 let queryRoot = params.get("page"); 53 58 let firstPage = queryRoot || rootPage?.data.value || props.rootPage; 54 59 let entity_set = useEntitySetContext(); 60 + let publication = usePublicationContext(); 55 61 56 62 return ( 57 63 <div ··· 71 77 <Media mobile={false} className="h-full"> 72 78 <div className="flex flex-col h-full justify-between mt-1"> 73 79 {entity_set.permissions.write ? ( 74 - <div className="flex flex-col justify-center gap-2 mr-4"> 80 + <div className=" flex flex-col justify-center gap-2 mr-4"> 81 + {publication.publication && ( 82 + <div className="relative w-[30px] h-[76px]"> 83 + <div className="origin-top-left -rotate-90 absolute translate-y-[76px]"> 84 + <PublishToPublication /> 85 + </div> 86 + </div> 87 + )} 75 88 <ShareOptions /> 76 - <LeafletOptions entityID={props.rootPage} /> 89 + <ThemePopover entityID={props.rootPage} /> 77 90 <HelpPopover /> 78 91 <hr className="text-border my-3" /> 79 92 <HomeButton />
+32
components/Providers/PublicationContext.tsx
··· 1 + "use client"; 2 + import { createContext, useContext, ReactNode } from "react"; 3 + 4 + interface PublicationContextType { 5 + publication: { uri: string; name: string } | null; 6 + } 7 + 8 + const PublicationContext = createContext<PublicationContextType | undefined>( 9 + undefined, 10 + ); 11 + 12 + export function PublicationContextProvider({ 13 + children, 14 + publication, 15 + }: { 16 + children: ReactNode; 17 + publication: PublicationContextType["publication"]; 18 + }) { 19 + return ( 20 + <PublicationContext.Provider value={{ publication }}> 21 + {children} 22 + </PublicationContext.Provider> 23 + ); 24 + } 25 + 26 + export function usePublicationContext() { 27 + const context = useContext(PublicationContext); 28 + if (context === undefined) { 29 + throw new Error("usePublication must be used within a PublicationProvider"); 30 + } 31 + return context; 32 + }
+160
components/ShareOptions/PublicationOptions.tsx
··· 1 + import { publishToPublication } from "actions/publishToPublication"; 2 + import { ButtonPrimary } from "components/Buttons"; 3 + import { useIdentityData } from "components/IdentityProvider"; 4 + import { InputWithLabel } from "components/Input"; 5 + import { useState } from "react"; 6 + import { Popover } from "components/Popover"; 7 + import { useBlocks } from "src/hooks/queries/useBlocks"; 8 + import { useEntity, useReplicache } from "src/replicache"; 9 + import { usePublicationContext } from "components/Providers/PublicationContext"; 10 + import { useRouter } from "next/navigation"; 11 + import Link from "next/link"; 12 + 13 + export const PublishToPublication = () => { 14 + type PublishState = 15 + | { state: "default" } 16 + | { state: "test" } 17 + | { state: "testSuccess" } 18 + | { state: "success"; link: string }; 19 + 20 + let [state, setState] = useState<PublishState>({ state: "default" }); 21 + let publication = usePublicationContext(); 22 + let rep = useReplicache(); 23 + let rootPage = useEntity(rep.rootEntity, "root/page")[0]; 24 + let blocks = useBlocks(rootPage?.data.value); 25 + let router = useRouter(); 26 + 27 + let [titleValue, setTitleValue] = useState(""); 28 + let [descriptionValue, setDescriptionValue] = useState(""); 29 + let [testValue, setTestValue] = useState(""); 30 + if (!publication.publication) return null; 31 + 32 + return ( 33 + <Popover 34 + onOpenChange={() => setState({ state: "default" })} 35 + asChild 36 + trigger={<ButtonPrimary className="">Publish</ButtonPrimary>} 37 + > 38 + <div className="publishMenu w-96 flex flex-col gap-3"> 39 + {state.state === "default" ? ( 40 + <> 41 + <div className="w-full flex flex-col"> 42 + <h3 className="place-self-start"> 43 + Publish to {publication.publication.name} 44 + </h3> 45 + {/* <small className="text-tertiary"> 46 + Publish this post to a PUBLICATION HERE and send it as an email 47 + to your XX subscribers. 48 + </small> */} 49 + </div> 50 + <form 51 + className="flex flex-col gap-3 w-full" 52 + onSubmit={async (e) => { 53 + e.preventDefault(); 54 + if (!publication.publication) return; 55 + let data = await publishToPublication( 56 + rep.rootEntity, 57 + blocks, 58 + publication.publication.uri, 59 + ); 60 + if (data) 61 + setState({ 62 + state: "success", 63 + link: `/lish/${data.handle?.alsoKnownAs?.[0].slice(5)}/${publication.publication.name}/${data.rkey}`, 64 + }); 65 + }} 66 + > 67 + <InputWithLabel 68 + label="Title" 69 + value={titleValue} 70 + onChange={(e) => { 71 + setTitleValue(e.currentTarget.value); 72 + }} 73 + /> 74 + <InputWithLabel 75 + textarea 76 + rows={3} 77 + label="Description" 78 + value={descriptionValue} 79 + onChange={(e) => { 80 + setDescriptionValue(e.currentTarget.value); 81 + }} 82 + /> 83 + <div className="flex gap-3 justify-end w-full"> 84 + {/* <button 85 + onClick={() => { 86 + setState({ state: "test" }); 87 + }} 88 + className="font-bold text-accent-contrast" 89 + > 90 + Send Test 91 + </button> */} 92 + <ButtonPrimary>Publish </ButtonPrimary> 93 + </div> 94 + </form> 95 + </> 96 + ) : state.state === "test" ? ( 97 + <> 98 + <h3>Send out a test</h3> 99 + <form 100 + className="flex flex-col gap-3" 101 + onSubmit={() => { 102 + setState({ state: "testSuccess" }); 103 + }} 104 + > 105 + <InputWithLabel 106 + label="Send to" 107 + placeholder="email here..." 108 + value={testValue} 109 + onChange={(e) => { 110 + setTestValue(e.currentTarget.value); 111 + }} 112 + /> 113 + 114 + <ButtonPrimary type="submit" className="place-self-end"> 115 + Send Test 116 + </ButtonPrimary> 117 + </form> 118 + </> 119 + ) : state.state === "testSuccess" ? ( 120 + <> 121 + <div 122 + className="w-full p-4 rounded-md flex flex-col text-center" 123 + style={{ 124 + backgroundColor: 125 + "color-mix(in oklab, rgb(var(--accent-contrast)), rgb(var(--bg-page)) 85%)", 126 + }} 127 + > 128 + <div>Sent! Check you email!</div> 129 + <div className="italic font-bold">{testValue}</div> 130 + <button 131 + onClick={() => { 132 + setState({ state: "default" }); 133 + }} 134 + className="w-fit mx-auto font-bold text-accent-contrast mt-3" 135 + > 136 + Back 137 + </button> 138 + </div> 139 + </> 140 + ) : state.state === "success" ? ( 141 + <div 142 + className="w-full p-4 rounded-md flex flex-col text-center" 143 + style={{ 144 + backgroundColor: 145 + "color-mix(in oklab, rgb(var(--accent-contrast)), rgb(var(--bg-page)) 85%)", 146 + }} 147 + > 148 + <div className="font-bold">Woot! It's Published!</div> 149 + <Link 150 + href={state.link} 151 + className="w-fit mx-auto font-bold text-accent-contrast mt-1" 152 + > 153 + View Post 154 + </Link> 155 + </div> 156 + ) : null} 157 + </div> 158 + </Popover> 159 + ); 160 + };
+3 -3
components/ShareOptions/index.tsx
··· 9 9 import useSWR from "swr"; 10 10 import { useTemplateState } from "app/home/CreateNewButton"; 11 11 import LoginForm from "app/login/LoginForm"; 12 - import { AddDomain, CustomDomainMenu, DomainOptions } from "./DomainOptions"; 12 + import { CustomDomainMenu } from "./DomainOptions"; 13 13 import { useIdentityData } from "components/IdentityProvider"; 14 14 import { useLeafletDomains } from "components/PageSWRDataProvider"; 15 15 ··· 63 63 ) : menuState === "domain" ? ( 64 64 <CustomDomainMenu setShareMenuState={setMenuState} /> 65 65 ) : ( 66 - <DefaultOptions setMenuState={setMenuState} domainConnected={false} /> 66 + <ShareMenu setMenuState={setMenuState} domainConnected={false} /> 67 67 )} 68 68 </Menu> 69 69 ); 70 70 } 71 71 72 - const DefaultOptions = (props: { 72 + const ShareMenu = (props: { 73 73 setMenuState: (state: ShareMenuStates) => void; 74 74 domainConnected: boolean; 75 75 }) => {
+2 -2
components/ThemeManager/ThemeSetter.tsx
··· 134 134 </Popover.Trigger> 135 135 <Popover.Portal> 136 136 <Popover.Content 137 - style={{ maxHeight: viewheight ? viewheight * 0.8 : "80vh" }} 138 - className="z-20 themeSetterWrapper w-80 h-fit bg-white rounded-md border border-border flex" 137 + className="z-20 themeSetterWrapper w-80 h-fit bg-white rounded-md border border-border flex max-w-[var(--radix-popover-content-available-width)] 138 + max-h-[var(--radix-popover-content-available-height)]" 139 139 align="center" 140 140 sideOffset={4} 141 141 collisionPadding={16}
+51 -1
drizzle/relations.ts
··· 1 1 import { relations } from "drizzle-orm/relations"; 2 - import { entities, facts, entity_sets, permission_tokens, identities, email_subscriptions_to_entity, email_auth_tokens, phone_rsvps_to_entity, custom_domains, custom_domain_routes, poll_votes_on_entity, permission_token_on_homepage, permission_token_rights } from "./schema"; 2 + import { entities, facts, entity_sets, permission_tokens, identities, email_subscriptions_to_entity, email_auth_tokens, phone_rsvps_to_entity, custom_domains, custom_domain_routes, poll_votes_on_entity, subscribers_to_publications, publications, permission_token_on_homepage, documents, documents_in_publications, leaflets_in_publications, permission_token_rights } from "./schema"; 3 3 4 4 export const factsRelations = relations(facts, ({one}) => ({ 5 5 entity: one(entities, { ··· 44 44 relationName: "custom_domain_routes_view_permission_token_permission_tokens_id" 45 45 }), 46 46 permission_token_on_homepages: many(permission_token_on_homepage), 47 + leaflets_in_publications: many(leaflets_in_publications), 47 48 permission_token_rights: many(permission_token_rights), 48 49 })); 49 50 ··· 54 55 }), 55 56 email_auth_tokens: many(email_auth_tokens), 56 57 custom_domains: many(custom_domains), 58 + subscribers_to_publications: many(subscribers_to_publications), 57 59 permission_token_on_homepages: many(permission_token_on_homepage), 58 60 })); 59 61 ··· 120 122 }), 121 123 })); 122 124 125 + export const subscribers_to_publicationsRelations = relations(subscribers_to_publications, ({one}) => ({ 126 + identity: one(identities, { 127 + fields: [subscribers_to_publications.identity], 128 + references: [identities.email] 129 + }), 130 + publication: one(publications, { 131 + fields: [subscribers_to_publications.publication], 132 + references: [publications.uri] 133 + }), 134 + })); 135 + 136 + export const publicationsRelations = relations(publications, ({many}) => ({ 137 + subscribers_to_publications: many(subscribers_to_publications), 138 + documents_in_publications: many(documents_in_publications), 139 + leaflets_in_publications: many(leaflets_in_publications), 140 + })); 141 + 123 142 export const permission_token_on_homepageRelations = relations(permission_token_on_homepage, ({one}) => ({ 124 143 identity: one(identities, { 125 144 fields: [permission_token_on_homepage.identity], ··· 128 147 permission_token: one(permission_tokens, { 129 148 fields: [permission_token_on_homepage.token], 130 149 references: [permission_tokens.id] 150 + }), 151 + })); 152 + 153 + export const documents_in_publicationsRelations = relations(documents_in_publications, ({one}) => ({ 154 + document: one(documents, { 155 + fields: [documents_in_publications.document], 156 + references: [documents.uri] 157 + }), 158 + publication: one(publications, { 159 + fields: [documents_in_publications.publication], 160 + references: [publications.uri] 161 + }), 162 + })); 163 + 164 + export const documentsRelations = relations(documents, ({many}) => ({ 165 + documents_in_publications: many(documents_in_publications), 166 + leaflets_in_publications: many(leaflets_in_publications), 167 + })); 168 + 169 + export const leaflets_in_publicationsRelations = relations(leaflets_in_publications, ({one}) => ({ 170 + document: one(documents, { 171 + fields: [leaflets_in_publications.doc], 172 + references: [documents.uri] 173 + }), 174 + permission_token: one(permission_tokens, { 175 + fields: [leaflets_in_publications.leaflet], 176 + references: [permission_tokens.id] 177 + }), 178 + publication: one(publications, { 179 + fields: [leaflets_in_publications.publication], 180 + references: [publications.uri] 131 181 }), 132 182 })); 133 183
+60 -2
drizzle/schema.ts
··· 1 - import { pgTable, foreignKey, pgEnum, uuid, text, jsonb, timestamp, bigint, boolean, unique, uniqueIndex, smallint, primaryKey } from "drizzle-orm/pg-core" 1 + import { pgTable, pgEnum, text, jsonb, timestamp, foreignKey, uuid, bigint, boolean, unique, uniqueIndex, smallint, primaryKey } from "drizzle-orm/pg-core" 2 2 import { sql } from "drizzle-orm" 3 3 4 4 export const aal_level = pgEnum("aal_level", ['aal1', 'aal2', 'aal3']) ··· 14 14 export const equality_op = pgEnum("equality_op", ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in']) 15 15 16 16 17 + export const oauth_state_store = pgTable("oauth_state_store", { 18 + key: text("key").primaryKey().notNull(), 19 + state: jsonb("state").notNull(), 20 + }); 21 + 22 + export const oauth_session_store = pgTable("oauth_session_store", { 23 + key: text("key").primaryKey().notNull(), 24 + session: jsonb("session").notNull(), 25 + }); 26 + 27 + export const publications = pgTable("publications", { 28 + uri: text("uri").primaryKey().notNull(), 29 + indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 30 + name: text("name").notNull(), 31 + identity_did: text("identity_did").notNull(), 32 + }); 33 + 17 34 export const facts = pgTable("facts", { 18 35 id: uuid("id").primaryKey().notNull(), 19 36 entity: uuid("entity").notNull().references(() => entities.id, { onDelete: "cascade", onUpdate: "restrict" } ), ··· 25 42 version: bigint("version", { mode: "number" }).default(0).notNull(), 26 43 }); 27 44 45 + export const documents = pgTable("documents", { 46 + uri: text("uri").primaryKey().notNull(), 47 + data: jsonb("data").notNull(), 48 + indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 49 + }); 50 + 28 51 export const replicache_clients = pgTable("replicache_clients", { 29 52 client_id: text("client_id").primaryKey().notNull(), 30 53 client_group: text("client_group").notNull(), ··· 54 77 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 55 78 home_page: uuid("home_page").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ), 56 79 email: text("email"), 80 + atp_did: text("atp_did"), 57 81 }, 58 82 (table) => { 59 83 return { 60 84 identities_email_key: unique("identities_email_key").on(table.email), 85 + identities_atp_did_key: unique("identities_atp_did_key").on(table.atp_did), 61 86 } 62 87 }); 63 88 ··· 75 100 id: uuid("id").defaultRandom().primaryKey().notNull(), 76 101 created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 77 102 confirmed: boolean("confirmed").default(false).notNull(), 78 - email: text("email").notNull(), 103 + email: text("email"), 79 104 confirmation_code: text("confirmation_code").notNull(), 80 105 identity: uuid("identity").references(() => identities.id, { onDelete: "cascade", onUpdate: "cascade" } ), 81 106 }); ··· 134 159 voter_token: uuid("voter_token").notNull(), 135 160 }); 136 161 162 + export const subscribers_to_publications = pgTable("subscribers_to_publications", { 163 + identity: text("identity").notNull().references(() => identities.email, { onUpdate: "cascade" } ), 164 + publication: text("publication").notNull().references(() => publications.uri), 165 + created_at: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 166 + }, 167 + (table) => { 168 + return { 169 + subscribers_to_publications_pkey: primaryKey({ columns: [table.identity, table.publication], name: "subscribers_to_publications_pkey"}), 170 + } 171 + }); 172 + 137 173 export const permission_token_on_homepage = pgTable("permission_token_on_homepage", { 138 174 token: uuid("token").notNull().references(() => permission_tokens.id, { onDelete: "cascade" } ), 139 175 identity: uuid("identity").notNull().references(() => identities.id, { onDelete: "cascade" } ), ··· 142 178 (table) => { 143 179 return { 144 180 permission_token_creator_pkey: primaryKey({ columns: [table.token, table.identity], name: "permission_token_creator_pkey"}), 181 + } 182 + }); 183 + 184 + export const documents_in_publications = pgTable("documents_in_publications", { 185 + publication: text("publication").notNull().references(() => publications.uri, { onDelete: "cascade" } ), 186 + document: text("document").notNull().references(() => documents.uri, { onDelete: "cascade" } ), 187 + indexed_at: timestamp("indexed_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(), 188 + }, 189 + (table) => { 190 + return { 191 + documents_in_publications_pkey: primaryKey({ columns: [table.publication, table.document], name: "documents_in_publications_pkey"}), 192 + } 193 + }); 194 + 195 + export const leaflets_in_publications = pgTable("leaflets_in_publications", { 196 + publication: text("publication").notNull().references(() => publications.uri), 197 + doc: text("doc").default('').references(() => documents.uri), 198 + leaflet: uuid("leaflet").notNull().references(() => permission_tokens.id), 199 + }, 200 + (table) => { 201 + return { 202 + leaflets_in_publications_pkey: primaryKey({ columns: [table.publication, table.leaflet], name: "leaflets_in_publications_pkey"}), 145 203 } 146 204 }); 147 205
+62
lexicons/blocks.ts
··· 1 + import * as l from "./utils"; 2 + 3 + export const PubLeafletBlocksText = l.lexicon({ 4 + id: "pub.leaflet.blocks.text", 5 + defs: { 6 + main: l.object({ 7 + required: [], 8 + properties: { 9 + plaintext: l.string(), 10 + }, 11 + }), 12 + }, 13 + }); 14 + 15 + export const PubLeafletBlocksHeader = l.lexicon({ 16 + id: "pub.leaflet.blocks.header", 17 + defs: { 18 + main: l.object({ 19 + required: [], 20 + properties: { 21 + level: l.integer({ minimum: 1, maximum: 6 }), 22 + plaintext: l.string(), 23 + }, 24 + }), 25 + }, 26 + }); 27 + 28 + export const PubLeafletBlocksImage = l.lexicon({ 29 + id: "pub.leaflet.blocks.image", 30 + defs: { 31 + main: l.object({ 32 + required: ["image", "aspectRatio"], 33 + properties: { 34 + image: l.blob({ accept: ["image/*"], maxSize: 1000000 }), 35 + alt: { 36 + type: "string", 37 + description: "Alt text description of the image, for accessibility.", 38 + }, 39 + aspectRatio: { 40 + type: "ref", 41 + ref: "#aspectRatio", 42 + }, 43 + }, 44 + }), 45 + aspectRatio: l.object({ 46 + required: ["width", "height"], 47 + properties: { 48 + width: l.integer(), 49 + height: l.integer(), 50 + }, 51 + }), 52 + }, 53 + }); 54 + 55 + export const BlockLexicons = [ 56 + PubLeafletBlocksText, 57 + PubLeafletBlocksHeader, 58 + PubLeafletBlocksImage, 59 + ]; 60 + export const BlockUnion = l.union({ 61 + refs: BlockLexicons.map((lexicon) => lexicon.id), 62 + });
+25
lexicons/build.ts
··· 1 + import * as PageLexicons from "./pages"; 2 + import { BlockLexicons } from "./blocks"; 3 + import { PubLeafletDocument } from "./document"; 4 + import * as PublicationLexicons from "./publication"; 5 + 6 + import * as fs from "fs"; 7 + import * as path from "path"; 8 + import { PublicKeyPage } from "twilio/lib/rest/accounts/v1/credential/publicKey"; 9 + const outdir = path.join("lexicons", "out"); 10 + 11 + fs.rmSync(outdir, { recursive: true }); 12 + fs.mkdirSync(outdir); 13 + 14 + const lexicons = [ 15 + PubLeafletDocument, 16 + PageLexicons.PubLeafletPagesLinearDocument, 17 + ...BlockLexicons, 18 + ...Object.values(PublicationLexicons), 19 + ]; 20 + 21 + // Write each lexicon to a file 22 + lexicons.forEach((lexicon) => { 23 + const filename = path.join(outdir, lexicon.id.replace(/\./g, "_") + ".json"); 24 + fs.writeFileSync(filename, JSON.stringify(lexicon, null, 2)); 25 + });
+156
lexicons/com/atproto/label/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.label.defs", 4 + "defs": { 5 + "label": { 6 + "type": "object", 7 + "description": "Metadata tag on an atproto resource (eg, repo or record).", 8 + "required": ["src", "uri", "val", "cts"], 9 + "properties": { 10 + "ver": { 11 + "type": "integer", 12 + "description": "The AT Protocol version of the label object." 13 + }, 14 + "src": { 15 + "type": "string", 16 + "format": "did", 17 + "description": "DID of the actor who created this label." 18 + }, 19 + "uri": { 20 + "type": "string", 21 + "format": "uri", 22 + "description": "AT URI of the record, repository (account), or other resource that this label applies to." 23 + }, 24 + "cid": { 25 + "type": "string", 26 + "format": "cid", 27 + "description": "Optionally, CID specifying the specific version of 'uri' resource this label applies to." 28 + }, 29 + "val": { 30 + "type": "string", 31 + "maxLength": 128, 32 + "description": "The short string name of the value or type of this label." 33 + }, 34 + "neg": { 35 + "type": "boolean", 36 + "description": "If true, this is a negation label, overwriting a previous label." 37 + }, 38 + "cts": { 39 + "type": "string", 40 + "format": "datetime", 41 + "description": "Timestamp when this label was created." 42 + }, 43 + "exp": { 44 + "type": "string", 45 + "format": "datetime", 46 + "description": "Timestamp at which this label expires (no longer applies)." 47 + }, 48 + "sig": { 49 + "type": "bytes", 50 + "description": "Signature of dag-cbor encoded label." 51 + } 52 + } 53 + }, 54 + "selfLabels": { 55 + "type": "object", 56 + "description": "Metadata tags on an atproto record, published by the author within the record.", 57 + "required": ["values"], 58 + "properties": { 59 + "values": { 60 + "type": "array", 61 + "items": { "type": "ref", "ref": "#selfLabel" }, 62 + "maxLength": 10 63 + } 64 + } 65 + }, 66 + "selfLabel": { 67 + "type": "object", 68 + "description": "Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.", 69 + "required": ["val"], 70 + "properties": { 71 + "val": { 72 + "type": "string", 73 + "maxLength": 128, 74 + "description": "The short string name of the value or type of this label." 75 + } 76 + } 77 + }, 78 + "labelValueDefinition": { 79 + "type": "object", 80 + "description": "Declares a label value and its expected interpretations and behaviors.", 81 + "required": ["identifier", "severity", "blurs", "locales"], 82 + "properties": { 83 + "identifier": { 84 + "type": "string", 85 + "description": "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).", 86 + "maxLength": 100, 87 + "maxGraphemes": 100 88 + }, 89 + "severity": { 90 + "type": "string", 91 + "description": "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.", 92 + "knownValues": ["inform", "alert", "none"] 93 + }, 94 + "blurs": { 95 + "type": "string", 96 + "description": "What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing.", 97 + "knownValues": ["content", "media", "none"] 98 + }, 99 + "defaultSetting": { 100 + "type": "string", 101 + "description": "The default setting for this label.", 102 + "knownValues": ["ignore", "warn", "hide"], 103 + "default": "warn" 104 + }, 105 + "adultOnly": { 106 + "type": "boolean", 107 + "description": "Does the user need to have adult content enabled in order to configure this label?" 108 + }, 109 + "locales": { 110 + "type": "array", 111 + "items": { "type": "ref", "ref": "#labelValueDefinitionStrings" } 112 + } 113 + } 114 + }, 115 + "labelValueDefinitionStrings": { 116 + "type": "object", 117 + "description": "Strings which describe the label in the UI, localized into a specific language.", 118 + "required": ["lang", "name", "description"], 119 + "properties": { 120 + "lang": { 121 + "type": "string", 122 + "description": "The code of the language these strings are written in.", 123 + "format": "language" 124 + }, 125 + "name": { 126 + "type": "string", 127 + "description": "A short human-readable name for the label.", 128 + "maxGraphemes": 64, 129 + "maxLength": 640 130 + }, 131 + "description": { 132 + "type": "string", 133 + "description": "A longer description of what the label means and why it might be applied.", 134 + "maxGraphemes": 10000, 135 + "maxLength": 100000 136 + } 137 + } 138 + }, 139 + "labelValue": { 140 + "type": "string", 141 + "knownValues": [ 142 + "!hide", 143 + "!no-promote", 144 + "!warn", 145 + "!no-unauthenticated", 146 + "dmca-violation", 147 + "doxxing", 148 + "porn", 149 + "sexual", 150 + "nudity", 151 + "nsfl", 152 + "gore" 153 + ] 154 + } 155 + } 156 + }
+131
lexicons/com/atproto/repo/applyWrites.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.applyWrites", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.", 8 + "input": { 9 + "encoding": "application/json", 10 + "schema": { 11 + "type": "object", 12 + "required": ["repo", "writes"], 13 + "properties": { 14 + "repo": { 15 + "type": "string", 16 + "format": "at-identifier", 17 + "description": "The handle or DID of the repo (aka, current account)." 18 + }, 19 + "validate": { 20 + "type": "boolean", 21 + "description": "Can be set to 'false' to skip Lexicon schema validation of record data across all operations, 'true' to require it, or leave unset to validate only for known Lexicons." 22 + }, 23 + "writes": { 24 + "type": "array", 25 + "items": { 26 + "type": "union", 27 + "refs": ["#create", "#update", "#delete"], 28 + "closed": true 29 + } 30 + }, 31 + "swapCommit": { 32 + "type": "string", 33 + "description": "If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.", 34 + "format": "cid" 35 + } 36 + } 37 + } 38 + }, 39 + "output": { 40 + "encoding": "application/json", 41 + "schema": { 42 + "type": "object", 43 + "required": [], 44 + "properties": { 45 + "commit": { 46 + "type": "ref", 47 + "ref": "com.atproto.repo.defs#commitMeta" 48 + }, 49 + "results": { 50 + "type": "array", 51 + "items": { 52 + "type": "union", 53 + "refs": ["#createResult", "#updateResult", "#deleteResult"], 54 + "closed": true 55 + } 56 + } 57 + } 58 + } 59 + }, 60 + "errors": [ 61 + { 62 + "name": "InvalidSwap", 63 + "description": "Indicates that the 'swapCommit' parameter did not match current commit." 64 + } 65 + ] 66 + }, 67 + "create": { 68 + "type": "object", 69 + "description": "Operation which creates a new record.", 70 + "required": ["collection", "value"], 71 + "properties": { 72 + "collection": { "type": "string", "format": "nsid" }, 73 + "rkey": { 74 + "type": "string", 75 + "maxLength": 512, 76 + "format": "record-key", 77 + "description": "NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility." 78 + }, 79 + "value": { "type": "unknown" } 80 + } 81 + }, 82 + "update": { 83 + "type": "object", 84 + "description": "Operation which updates an existing record.", 85 + "required": ["collection", "rkey", "value"], 86 + "properties": { 87 + "collection": { "type": "string", "format": "nsid" }, 88 + "rkey": { "type": "string", "format": "record-key" }, 89 + "value": { "type": "unknown" } 90 + } 91 + }, 92 + "delete": { 93 + "type": "object", 94 + "description": "Operation which deletes an existing record.", 95 + "required": ["collection", "rkey"], 96 + "properties": { 97 + "collection": { "type": "string", "format": "nsid" }, 98 + "rkey": { "type": "string", "format": "record-key" } 99 + } 100 + }, 101 + "createResult": { 102 + "type": "object", 103 + "required": ["uri", "cid"], 104 + "properties": { 105 + "uri": { "type": "string", "format": "at-uri" }, 106 + "cid": { "type": "string", "format": "cid" }, 107 + "validationStatus": { 108 + "type": "string", 109 + "knownValues": ["valid", "unknown"] 110 + } 111 + } 112 + }, 113 + "updateResult": { 114 + "type": "object", 115 + "required": ["uri", "cid"], 116 + "properties": { 117 + "uri": { "type": "string", "format": "at-uri" }, 118 + "cid": { "type": "string", "format": "cid" }, 119 + "validationStatus": { 120 + "type": "string", 121 + "knownValues": ["valid", "unknown"] 122 + } 123 + } 124 + }, 125 + "deleteResult": { 126 + "type": "object", 127 + "required": [], 128 + "properties": {} 129 + } 130 + } 131 + }
+73
lexicons/com/atproto/repo/createRecord.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.createRecord", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Create a single new repository record. Requires auth, implemented by PDS.", 8 + "input": { 9 + "encoding": "application/json", 10 + "schema": { 11 + "type": "object", 12 + "required": ["repo", "collection", "record"], 13 + "properties": { 14 + "repo": { 15 + "type": "string", 16 + "format": "at-identifier", 17 + "description": "The handle or DID of the repo (aka, current account)." 18 + }, 19 + "collection": { 20 + "type": "string", 21 + "format": "nsid", 22 + "description": "The NSID of the record collection." 23 + }, 24 + "rkey": { 25 + "type": "string", 26 + "format": "record-key", 27 + "description": "The Record Key.", 28 + "maxLength": 512 29 + }, 30 + "validate": { 31 + "type": "boolean", 32 + "description": "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons." 33 + }, 34 + "record": { 35 + "type": "unknown", 36 + "description": "The record itself. Must contain a $type field." 37 + }, 38 + "swapCommit": { 39 + "type": "string", 40 + "format": "cid", 41 + "description": "Compare and swap with the previous commit by CID." 42 + } 43 + } 44 + } 45 + }, 46 + "output": { 47 + "encoding": "application/json", 48 + "schema": { 49 + "type": "object", 50 + "required": ["uri", "cid"], 51 + "properties": { 52 + "uri": { "type": "string", "format": "at-uri" }, 53 + "cid": { "type": "string", "format": "cid" }, 54 + "commit": { 55 + "type": "ref", 56 + "ref": "com.atproto.repo.defs#commitMeta" 57 + }, 58 + "validationStatus": { 59 + "type": "string", 60 + "knownValues": ["valid", "unknown"] 61 + } 62 + } 63 + } 64 + }, 65 + "errors": [ 66 + { 67 + "name": "InvalidSwap", 68 + "description": "Indicates that 'swapCommit' didn't match current repo commit." 69 + } 70 + ] 71 + } 72 + } 73 + }
+14
lexicons/com/atproto/repo/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.defs", 4 + "defs": { 5 + "commitMeta": { 6 + "type": "object", 7 + "required": ["cid", "rev"], 8 + "properties": { 9 + "cid": { "type": "string", "format": "cid" }, 10 + "rev": { "type": "string", "format": "tid" } 11 + } 12 + } 13 + } 14 + }
+57
lexicons/com/atproto/repo/deleteRecord.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.deleteRecord", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", 8 + "input": { 9 + "encoding": "application/json", 10 + "schema": { 11 + "type": "object", 12 + "required": ["repo", "collection", "rkey"], 13 + "properties": { 14 + "repo": { 15 + "type": "string", 16 + "format": "at-identifier", 17 + "description": "The handle or DID of the repo (aka, current account)." 18 + }, 19 + "collection": { 20 + "type": "string", 21 + "format": "nsid", 22 + "description": "The NSID of the record collection." 23 + }, 24 + "rkey": { 25 + "type": "string", 26 + "format": "record-key", 27 + "description": "The Record Key." 28 + }, 29 + "swapRecord": { 30 + "type": "string", 31 + "format": "cid", 32 + "description": "Compare and swap with the previous record by CID." 33 + }, 34 + "swapCommit": { 35 + "type": "string", 36 + "format": "cid", 37 + "description": "Compare and swap with the previous commit by CID." 38 + } 39 + } 40 + } 41 + }, 42 + "output": { 43 + "encoding": "application/json", 44 + "schema": { 45 + "type": "object", 46 + "properties": { 47 + "commit": { 48 + "type": "ref", 49 + "ref": "com.atproto.repo.defs#commitMeta" 50 + } 51 + } 52 + } 53 + }, 54 + "errors": [{ "name": "InvalidSwap" }] 55 + } 56 + } 57 + }
+51
lexicons/com/atproto/repo/describeRepo.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.describeRepo", 4 + "defs": { 5 + "main": { 6 + "type": "query", 7 + "description": "Get information about an account and repository, including the list of collections. Does not require auth.", 8 + "parameters": { 9 + "type": "params", 10 + "required": ["repo"], 11 + "properties": { 12 + "repo": { 13 + "type": "string", 14 + "format": "at-identifier", 15 + "description": "The handle or DID of the repo." 16 + } 17 + } 18 + }, 19 + "output": { 20 + "encoding": "application/json", 21 + "schema": { 22 + "type": "object", 23 + "required": [ 24 + "handle", 25 + "did", 26 + "didDoc", 27 + "collections", 28 + "handleIsCorrect" 29 + ], 30 + "properties": { 31 + "handle": { "type": "string", "format": "handle" }, 32 + "did": { "type": "string", "format": "did" }, 33 + "didDoc": { 34 + "type": "unknown", 35 + "description": "The complete DID document for this account." 36 + }, 37 + "collections": { 38 + "type": "array", 39 + "description": "List of all the collections (NSIDs) for which this repo contains at least one record.", 40 + "items": { "type": "string", "format": "nsid" } 41 + }, 42 + "handleIsCorrect": { 43 + "type": "boolean", 44 + "description": "Indicates if handle is currently valid (resolves bi-directionally)" 45 + } 46 + } 47 + } 48 + } 49 + } 50 + } 51 + }
+49
lexicons/com/atproto/repo/getRecord.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.getRecord", 4 + "defs": { 5 + "main": { 6 + "type": "query", 7 + "description": "Get a single record from a repository. Does not require auth.", 8 + "parameters": { 9 + "type": "params", 10 + "required": ["repo", "collection", "rkey"], 11 + "properties": { 12 + "repo": { 13 + "type": "string", 14 + "format": "at-identifier", 15 + "description": "The handle or DID of the repo." 16 + }, 17 + "collection": { 18 + "type": "string", 19 + "format": "nsid", 20 + "description": "The NSID of the record collection." 21 + }, 22 + "rkey": { 23 + "type": "string", 24 + "description": "The Record Key.", 25 + "format": "record-key" 26 + }, 27 + "cid": { 28 + "type": "string", 29 + "format": "cid", 30 + "description": "The CID of the version of the record. If not specified, then return the most recent version." 31 + } 32 + } 33 + }, 34 + "output": { 35 + "encoding": "application/json", 36 + "schema": { 37 + "type": "object", 38 + "required": ["uri", "value"], 39 + "properties": { 40 + "uri": { "type": "string", "format": "at-uri" }, 41 + "cid": { "type": "string", "format": "cid" }, 42 + "value": { "type": "unknown" } 43 + } 44 + } 45 + }, 46 + "errors": [{ "name": "RecordNotFound" }] 47 + } 48 + } 49 + }
+13
lexicons/com/atproto/repo/importRepo.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.importRepo", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.", 8 + "input": { 9 + "encoding": "application/vnd.ipld.car" 10 + } 11 + } 12 + } 13 + }
+44
lexicons/com/atproto/repo/listMissingBlobs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.listMissingBlobs", 4 + "defs": { 5 + "main": { 6 + "type": "query", 7 + "description": "Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.", 8 + "parameters": { 9 + "type": "params", 10 + "properties": { 11 + "limit": { 12 + "type": "integer", 13 + "minimum": 1, 14 + "maximum": 1000, 15 + "default": 500 16 + }, 17 + "cursor": { "type": "string" } 18 + } 19 + }, 20 + "output": { 21 + "encoding": "application/json", 22 + "schema": { 23 + "type": "object", 24 + "required": ["blobs"], 25 + "properties": { 26 + "cursor": { "type": "string" }, 27 + "blobs": { 28 + "type": "array", 29 + "items": { "type": "ref", "ref": "#recordBlob" } 30 + } 31 + } 32 + } 33 + } 34 + }, 35 + "recordBlob": { 36 + "type": "object", 37 + "required": ["cid", "recordUri"], 38 + "properties": { 39 + "cid": { "type": "string", "format": "cid" }, 40 + "recordUri": { "type": "string", "format": "at-uri" } 41 + } 42 + } 43 + } 44 + }
+69
lexicons/com/atproto/repo/listRecords.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.listRecords", 4 + "defs": { 5 + "main": { 6 + "type": "query", 7 + "description": "List a range of records in a repository, matching a specific collection. Does not require auth.", 8 + "parameters": { 9 + "type": "params", 10 + "required": ["repo", "collection"], 11 + "properties": { 12 + "repo": { 13 + "type": "string", 14 + "format": "at-identifier", 15 + "description": "The handle or DID of the repo." 16 + }, 17 + "collection": { 18 + "type": "string", 19 + "format": "nsid", 20 + "description": "The NSID of the record type." 21 + }, 22 + "limit": { 23 + "type": "integer", 24 + "minimum": 1, 25 + "maximum": 100, 26 + "default": 50, 27 + "description": "The number of records to return." 28 + }, 29 + "cursor": { "type": "string" }, 30 + "rkeyStart": { 31 + "type": "string", 32 + "description": "DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)" 33 + }, 34 + "rkeyEnd": { 35 + "type": "string", 36 + "description": "DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)" 37 + }, 38 + "reverse": { 39 + "type": "boolean", 40 + "description": "Flag to reverse the order of the returned records." 41 + } 42 + } 43 + }, 44 + "output": { 45 + "encoding": "application/json", 46 + "schema": { 47 + "type": "object", 48 + "required": ["records"], 49 + "properties": { 50 + "cursor": { "type": "string" }, 51 + "records": { 52 + "type": "array", 53 + "items": { "type": "ref", "ref": "#record" } 54 + } 55 + } 56 + } 57 + } 58 + }, 59 + "record": { 60 + "type": "object", 61 + "required": ["uri", "cid", "value"], 62 + "properties": { 63 + "uri": { "type": "string", "format": "at-uri" }, 64 + "cid": { "type": "string", "format": "cid" }, 65 + "value": { "type": "unknown" } 66 + } 67 + } 68 + } 69 + }
+74
lexicons/com/atproto/repo/putRecord.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.putRecord", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.", 8 + "input": { 9 + "encoding": "application/json", 10 + "schema": { 11 + "type": "object", 12 + "required": ["repo", "collection", "rkey", "record"], 13 + "nullable": ["swapRecord"], 14 + "properties": { 15 + "repo": { 16 + "type": "string", 17 + "format": "at-identifier", 18 + "description": "The handle or DID of the repo (aka, current account)." 19 + }, 20 + "collection": { 21 + "type": "string", 22 + "format": "nsid", 23 + "description": "The NSID of the record collection." 24 + }, 25 + "rkey": { 26 + "type": "string", 27 + "format": "record-key", 28 + "description": "The Record Key.", 29 + "maxLength": 512 30 + }, 31 + "validate": { 32 + "type": "boolean", 33 + "description": "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons." 34 + }, 35 + "record": { 36 + "type": "unknown", 37 + "description": "The record to write." 38 + }, 39 + "swapRecord": { 40 + "type": "string", 41 + "format": "cid", 42 + "description": "Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation" 43 + }, 44 + "swapCommit": { 45 + "type": "string", 46 + "format": "cid", 47 + "description": "Compare and swap with the previous commit by CID." 48 + } 49 + } 50 + } 51 + }, 52 + "output": { 53 + "encoding": "application/json", 54 + "schema": { 55 + "type": "object", 56 + "required": ["uri", "cid"], 57 + "properties": { 58 + "uri": { "type": "string", "format": "at-uri" }, 59 + "cid": { "type": "string", "format": "cid" }, 60 + "commit": { 61 + "type": "ref", 62 + "ref": "com.atproto.repo.defs#commitMeta" 63 + }, 64 + "validationStatus": { 65 + "type": "string", 66 + "knownValues": ["valid", "unknown"] 67 + } 68 + } 69 + } 70 + }, 71 + "errors": [{ "name": "InvalidSwap" }] 72 + } 73 + } 74 + }
+15
lexicons/com/atproto/repo/strongRef.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.strongRef", 4 + "description": "A URI with a content-hash fingerprint.", 5 + "defs": { 6 + "main": { 7 + "type": "object", 8 + "required": ["uri", "cid"], 9 + "properties": { 10 + "uri": { "type": "string", "format": "at-uri" }, 11 + "cid": { "type": "string", "format": "cid" } 12 + } 13 + } 14 + } 15 + }
+23
lexicons/com/atproto/repo/uploadBlob.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.uploadBlob", 4 + "defs": { 5 + "main": { 6 + "type": "procedure", 7 + "description": "Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.", 8 + "input": { 9 + "encoding": "*/*" 10 + }, 11 + "output": { 12 + "encoding": "application/json", 13 + "schema": { 14 + "type": "object", 15 + "required": ["blob"], 16 + "properties": { 17 + "blob": { "type": "blob" } 18 + } 19 + } 20 + } 21 + } 22 + } 23 + }
+26
lexicons/document.ts
··· 1 + import { PubLeafletPagesLinearDocument } from "./pages/LinearDocument"; 2 + import * as l from "./utils"; 3 + 4 + export const PubLeafletDocument = l.lexicon({ 5 + id: "pub.leaflet.document", 6 + revision: 1, 7 + description: "A lexicon for long form rich media documents", 8 + defs: { 9 + main: l.record({ 10 + key: "tid", 11 + description: "Record containing a document", 12 + record: l.object({ 13 + required: ["pages", "author", "title", "publication"], 14 + properties: { 15 + title: l.string({ maxLength: 128 }), 16 + publishedAt: l.string({ format: "datetime" }), 17 + publication: l.string({ format: "at-uri" }), 18 + author: l.string({ format: "at-identifier" }), 19 + pages: l.array({ 20 + items: l.union({ refs: [PubLeafletPagesLinearDocument.id] }), 21 + }), 22 + }, 23 + }), 24 + }), 25 + }, 26 + });
+20
lexicons/out/pub_leaflet_blocks_header.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.blocks.header", 4 + "defs": { 5 + "main": { 6 + "type": "object", 7 + "required": [], 8 + "properties": { 9 + "level": { 10 + "type": "integer", 11 + "minimum": 1, 12 + "maximum": 6 13 + }, 14 + "plaintext": { 15 + "type": "string" 16 + } 17 + } 18 + } 19 + } 20 + }
+44
lexicons/out/pub_leaflet_blocks_image.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.blocks.image", 4 + "defs": { 5 + "main": { 6 + "type": "object", 7 + "required": [ 8 + "image" 9 + ], 10 + "properties": { 11 + "image": { 12 + "type": "blob", 13 + "accept": [ 14 + "image/*" 15 + ], 16 + "maxSize": 1000000 17 + }, 18 + "alt": { 19 + "type": "string", 20 + "description": "Alt text description of the image, for accessibility." 21 + }, 22 + "aspectRatio": { 23 + "type": "ref", 24 + "ref": "#aspectRatio" 25 + } 26 + } 27 + }, 28 + "aspectRatio": { 29 + "type": "object", 30 + "required": [ 31 + "width", 32 + "height" 33 + ], 34 + "properties": { 35 + "width": { 36 + "type": "integer" 37 + }, 38 + "height": { 39 + "type": "integer" 40 + } 41 + } 42 + } 43 + } 44 + }
+15
lexicons/out/pub_leaflet_blocks_text.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.blocks.text", 4 + "defs": { 5 + "main": { 6 + "type": "object", 7 + "required": [], 8 + "properties": { 9 + "plaintext": { 10 + "type": "string" 11 + } 12 + } 13 + } 14 + } 15 + }
+49
lexicons/out/pub_leaflet_document.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.document", 4 + "revision": 1, 5 + "description": "A lexicon for long form rich media documents", 6 + "defs": { 7 + "main": { 8 + "type": "record", 9 + "key": "tid", 10 + "description": "Record containing a document", 11 + "record": { 12 + "type": "object", 13 + "required": [ 14 + "pages", 15 + "author", 16 + "title", 17 + "publication" 18 + ], 19 + "properties": { 20 + "title": { 21 + "type": "string", 22 + "maxLength": 128 23 + }, 24 + "publishedAt": { 25 + "type": "string", 26 + "format": "datetime" 27 + }, 28 + "publication": { 29 + "type": "string", 30 + "format": "at-uri" 31 + }, 32 + "author": { 33 + "type": "string", 34 + "format": "at-identifier" 35 + }, 36 + "pages": { 37 + "type": "array", 38 + "items": { 39 + "type": "union", 40 + "refs": [ 41 + "pub.leaflet.pages.linearDocument" 42 + ] 43 + } 44 + } 45 + } 46 + } 47 + } 48 + } 49 + }
+51
lexicons/out/pub_leaflet_pages_linearDocument.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.pages.linearDocument", 4 + "defs": { 5 + "main": { 6 + "type": "object", 7 + "properties": { 8 + "blocks": { 9 + "type": "array", 10 + "items": { 11 + "type": "ref", 12 + "ref": "#block" 13 + } 14 + } 15 + } 16 + }, 17 + "block": { 18 + "type": "object", 19 + "required": [ 20 + "block" 21 + ], 22 + "properties": { 23 + "block": { 24 + "type": "union", 25 + "refs": [ 26 + "pub.leaflet.blocks.text", 27 + "pub.leaflet.blocks.header", 28 + "pub.leaflet.blocks.image" 29 + ] 30 + }, 31 + "alignment": { 32 + "type": "string", 33 + "knownValues": [ 34 + "#textAlignLeft", 35 + "#textAlignCenter", 36 + "#textAlignRight" 37 + ] 38 + } 39 + } 40 + }, 41 + "textAlignLeft": { 42 + "type": "token" 43 + }, 44 + "textAlignCenter": { 45 + "type": "token" 46 + }, 47 + "textAlignRight": { 48 + "type": "token" 49 + } 50 + } 51 + }
+32
lexicons/out/pub_leaflet_post.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.post", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "description": "Record putting a post in a document", 9 + "record": { 10 + "type": "object", 11 + "required": [ 12 + "post", 13 + "publishedAt" 14 + ], 15 + "properties": { 16 + "publication": { 17 + "type": "string", 18 + "format": "at-uri" 19 + }, 20 + "post": { 21 + "type": "ref", 22 + "ref": "com.atproto.repo.strongRef" 23 + }, 24 + "publishedAt": { 25 + "type": "string", 26 + "format": "datetime" 27 + } 28 + } 29 + } 30 + } 31 + } 32 + }
+27
lexicons/out/pub_leaflet_publication.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.publication", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "description": "Record declaring a publication", 9 + "record": { 10 + "type": "object", 11 + "required": [ 12 + "name" 13 + ], 14 + "properties": { 15 + "name": { 16 + "type": "string", 17 + "maxLength": 2000 18 + }, 19 + "description": { 20 + "type": "string", 21 + "maxLength": 2000 22 + } 23 + } 24 + } 25 + } 26 + } 27 + }
+36
lexicons/pages/LinearDocument.ts
··· 1 + import { BlockUnion } from "../blocks"; 2 + import * as l from "../utils"; 3 + 4 + const textAlignRefs = { 5 + id: "ignore", 6 + defs: { 7 + textAlignLeft: l.token(), 8 + textAlignCenter: l.token(), 9 + textAlignRight: l.token(), 10 + }, 11 + }; 12 + 13 + export const PubLeafletPagesLinearDocument = l.lexicon({ 14 + id: "pub.leaflet.pages.linearDocument", 15 + defs: { 16 + main: l.object({ 17 + properties: { 18 + blocks: { type: "array", items: l.ref("#block") }, 19 + }, 20 + }), 21 + block: l.object({ 22 + required: ["block"], 23 + properties: { 24 + block: BlockUnion, 25 + alignment: l.string({ 26 + knownValues: [ 27 + l.refValue<typeof textAlignRefs>(null, "textAlignLeft"), 28 + l.refValue<typeof textAlignRefs>(null, "textAlignCenter"), 29 + l.refValue<typeof textAlignRefs>(null, "textAlignRight"), 30 + ], 31 + }), 32 + }, 33 + }), 34 + ...textAlignRefs.defs, 35 + }, 36 + });
+1
lexicons/pages/index.ts
··· 1 + export { PubLeafletPagesLinearDocument } from "./LinearDocument";
+35
lexicons/publication.ts
··· 1 + import * as l from "./utils"; 2 + export const PubLeafletPublication = l.lexicon({ 3 + id: "pub.leaflet.publication", 4 + defs: { 5 + main: l.record({ 6 + key: "tid", 7 + description: "Record declaring a publication", 8 + record: l.object({ 9 + required: ["name"], 10 + properties: { 11 + name: l.string({ maxLength: 2000 }), 12 + description: l.string({ maxLength: 2000 }), 13 + }, 14 + }), 15 + }), 16 + }, 17 + }); 18 + 19 + export const PubLeafletPublicationPost = l.lexicon({ 20 + id: "pub.leaflet.post", 21 + defs: { 22 + main: l.record({ 23 + key: "tid", 24 + description: "Record putting a post in a document", 25 + record: l.object({ 26 + required: ["post", "publishedAt"], 27 + properties: { 28 + publication: l.string({ format: "at-uri" }), 29 + post: { type: "ref", ref: "com.atproto.repo.strongRef" }, 30 + publishedAt: { type: "string", format: "datetime" }, 31 + }, 32 + }), 33 + }), 34 + }, 35 + });
+446
lexicons/src/index.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { XrpcClient, FetchHandler, FetchHandlerOptions } from '@atproto/xrpc' 5 + import { schemas } from './lexicons.js' 6 + import { CID } from 'multiformats/cid' 7 + import { OmitKey, Un$Typed } from './util.js' 8 + import * as PubLeafletBlocksHeader from './types/pub/leaflet/blocks/header.js' 9 + import * as PubLeafletBlocksImage from './types/pub/leaflet/blocks/image.js' 10 + import * as PubLeafletBlocksText from './types/pub/leaflet/blocks/text.js' 11 + import * as PubLeafletDocument from './types/pub/leaflet/document.js' 12 + import * as PubLeafletPagesLinearDocument from './types/pub/leaflet/pages/linearDocument.js' 13 + import * as PubLeafletPost from './types/pub/leaflet/post.js' 14 + import * as PubLeafletPublication from './types/pub/leaflet/publication.js' 15 + import * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.js' 16 + import * as ComAtprotoRepoApplyWrites from './types/com/atproto/repo/applyWrites.js' 17 + import * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createRecord.js' 18 + import * as ComAtprotoRepoDefs from './types/com/atproto/repo/defs.js' 19 + import * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord.js' 20 + import * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo.js' 21 + import * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord.js' 22 + import * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo.js' 23 + import * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs.js' 24 + import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords.js' 25 + import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord.js' 26 + import * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.js' 27 + import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob.js' 28 + 29 + export * as PubLeafletBlocksHeader from './types/pub/leaflet/blocks/header.js' 30 + export * as PubLeafletBlocksImage from './types/pub/leaflet/blocks/image.js' 31 + export * as PubLeafletBlocksText from './types/pub/leaflet/blocks/text.js' 32 + export * as PubLeafletDocument from './types/pub/leaflet/document.js' 33 + export * as PubLeafletPagesLinearDocument from './types/pub/leaflet/pages/linearDocument.js' 34 + export * as PubLeafletPost from './types/pub/leaflet/post.js' 35 + export * as PubLeafletPublication from './types/pub/leaflet/publication.js' 36 + export * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.js' 37 + export * as ComAtprotoRepoApplyWrites from './types/com/atproto/repo/applyWrites.js' 38 + export * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createRecord.js' 39 + export * as ComAtprotoRepoDefs from './types/com/atproto/repo/defs.js' 40 + export * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord.js' 41 + export * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo.js' 42 + export * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord.js' 43 + export * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo.js' 44 + export * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs.js' 45 + export * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords.js' 46 + export * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord.js' 47 + export * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.js' 48 + export * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob.js' 49 + 50 + export const PUB_LEAFLET_PAGES = { 51 + LinearDocumentTextAlignLeft: 'pub.leaflet.pages.linearDocument#textAlignLeft', 52 + LinearDocumentTextAlignCenter: 53 + 'pub.leaflet.pages.linearDocument#textAlignCenter', 54 + LinearDocumentTextAlignRight: 55 + 'pub.leaflet.pages.linearDocument#textAlignRight', 56 + } 57 + 58 + export class AtpBaseClient extends XrpcClient { 59 + pub: PubNS 60 + com: ComNS 61 + 62 + constructor(options: FetchHandler | FetchHandlerOptions) { 63 + super(options, schemas) 64 + this.pub = new PubNS(this) 65 + this.com = new ComNS(this) 66 + } 67 + 68 + /** @deprecated use `this` instead */ 69 + get xrpc(): XrpcClient { 70 + return this 71 + } 72 + } 73 + 74 + export class PubNS { 75 + _client: XrpcClient 76 + leaflet: PubLeafletNS 77 + 78 + constructor(client: XrpcClient) { 79 + this._client = client 80 + this.leaflet = new PubLeafletNS(client) 81 + } 82 + } 83 + 84 + export class PubLeafletNS { 85 + _client: XrpcClient 86 + document: DocumentRecord 87 + post: PostRecord 88 + publication: PublicationRecord 89 + blocks: PubLeafletBlocksNS 90 + pages: PubLeafletPagesNS 91 + 92 + constructor(client: XrpcClient) { 93 + this._client = client 94 + this.blocks = new PubLeafletBlocksNS(client) 95 + this.pages = new PubLeafletPagesNS(client) 96 + this.document = new DocumentRecord(client) 97 + this.post = new PostRecord(client) 98 + this.publication = new PublicationRecord(client) 99 + } 100 + } 101 + 102 + export class PubLeafletBlocksNS { 103 + _client: XrpcClient 104 + 105 + constructor(client: XrpcClient) { 106 + this._client = client 107 + } 108 + } 109 + 110 + export class PubLeafletPagesNS { 111 + _client: XrpcClient 112 + 113 + constructor(client: XrpcClient) { 114 + this._client = client 115 + } 116 + } 117 + 118 + export class DocumentRecord { 119 + _client: XrpcClient 120 + 121 + constructor(client: XrpcClient) { 122 + this._client = client 123 + } 124 + 125 + async list( 126 + params: OmitKey<ComAtprotoRepoListRecords.QueryParams, 'collection'>, 127 + ): Promise<{ 128 + cursor?: string 129 + records: { uri: string; value: PubLeafletDocument.Record }[] 130 + }> { 131 + const res = await this._client.call('com.atproto.repo.listRecords', { 132 + collection: 'pub.leaflet.document', 133 + ...params, 134 + }) 135 + return res.data 136 + } 137 + 138 + async get( 139 + params: OmitKey<ComAtprotoRepoGetRecord.QueryParams, 'collection'>, 140 + ): Promise<{ uri: string; cid: string; value: PubLeafletDocument.Record }> { 141 + const res = await this._client.call('com.atproto.repo.getRecord', { 142 + collection: 'pub.leaflet.document', 143 + ...params, 144 + }) 145 + return res.data 146 + } 147 + 148 + async create( 149 + params: OmitKey< 150 + ComAtprotoRepoCreateRecord.InputSchema, 151 + 'collection' | 'record' 152 + >, 153 + record: Un$Typed<PubLeafletDocument.Record>, 154 + headers?: Record<string, string>, 155 + ): Promise<{ uri: string; cid: string }> { 156 + const collection = 'pub.leaflet.document' 157 + const res = await this._client.call( 158 + 'com.atproto.repo.createRecord', 159 + undefined, 160 + { collection, ...params, record: { ...record, $type: collection } }, 161 + { encoding: 'application/json', headers }, 162 + ) 163 + return res.data 164 + } 165 + 166 + async delete( 167 + params: OmitKey<ComAtprotoRepoDeleteRecord.InputSchema, 'collection'>, 168 + headers?: Record<string, string>, 169 + ): Promise<void> { 170 + await this._client.call( 171 + 'com.atproto.repo.deleteRecord', 172 + undefined, 173 + { collection: 'pub.leaflet.document', ...params }, 174 + { headers }, 175 + ) 176 + } 177 + } 178 + 179 + export class PostRecord { 180 + _client: XrpcClient 181 + 182 + constructor(client: XrpcClient) { 183 + this._client = client 184 + } 185 + 186 + async list( 187 + params: OmitKey<ComAtprotoRepoListRecords.QueryParams, 'collection'>, 188 + ): Promise<{ 189 + cursor?: string 190 + records: { uri: string; value: PubLeafletPost.Record }[] 191 + }> { 192 + const res = await this._client.call('com.atproto.repo.listRecords', { 193 + collection: 'pub.leaflet.post', 194 + ...params, 195 + }) 196 + return res.data 197 + } 198 + 199 + async get( 200 + params: OmitKey<ComAtprotoRepoGetRecord.QueryParams, 'collection'>, 201 + ): Promise<{ uri: string; cid: string; value: PubLeafletPost.Record }> { 202 + const res = await this._client.call('com.atproto.repo.getRecord', { 203 + collection: 'pub.leaflet.post', 204 + ...params, 205 + }) 206 + return res.data 207 + } 208 + 209 + async create( 210 + params: OmitKey< 211 + ComAtprotoRepoCreateRecord.InputSchema, 212 + 'collection' | 'record' 213 + >, 214 + record: Un$Typed<PubLeafletPost.Record>, 215 + headers?: Record<string, string>, 216 + ): Promise<{ uri: string; cid: string }> { 217 + const collection = 'pub.leaflet.post' 218 + const res = await this._client.call( 219 + 'com.atproto.repo.createRecord', 220 + undefined, 221 + { collection, ...params, record: { ...record, $type: collection } }, 222 + { encoding: 'application/json', headers }, 223 + ) 224 + return res.data 225 + } 226 + 227 + async delete( 228 + params: OmitKey<ComAtprotoRepoDeleteRecord.InputSchema, 'collection'>, 229 + headers?: Record<string, string>, 230 + ): Promise<void> { 231 + await this._client.call( 232 + 'com.atproto.repo.deleteRecord', 233 + undefined, 234 + { collection: 'pub.leaflet.post', ...params }, 235 + { headers }, 236 + ) 237 + } 238 + } 239 + 240 + export class PublicationRecord { 241 + _client: XrpcClient 242 + 243 + constructor(client: XrpcClient) { 244 + this._client = client 245 + } 246 + 247 + async list( 248 + params: OmitKey<ComAtprotoRepoListRecords.QueryParams, 'collection'>, 249 + ): Promise<{ 250 + cursor?: string 251 + records: { uri: string; value: PubLeafletPublication.Record }[] 252 + }> { 253 + const res = await this._client.call('com.atproto.repo.listRecords', { 254 + collection: 'pub.leaflet.publication', 255 + ...params, 256 + }) 257 + return res.data 258 + } 259 + 260 + async get( 261 + params: OmitKey<ComAtprotoRepoGetRecord.QueryParams, 'collection'>, 262 + ): Promise<{ 263 + uri: string 264 + cid: string 265 + value: PubLeafletPublication.Record 266 + }> { 267 + const res = await this._client.call('com.atproto.repo.getRecord', { 268 + collection: 'pub.leaflet.publication', 269 + ...params, 270 + }) 271 + return res.data 272 + } 273 + 274 + async create( 275 + params: OmitKey< 276 + ComAtprotoRepoCreateRecord.InputSchema, 277 + 'collection' | 'record' 278 + >, 279 + record: Un$Typed<PubLeafletPublication.Record>, 280 + headers?: Record<string, string>, 281 + ): Promise<{ uri: string; cid: string }> { 282 + const collection = 'pub.leaflet.publication' 283 + const res = await this._client.call( 284 + 'com.atproto.repo.createRecord', 285 + undefined, 286 + { collection, ...params, record: { ...record, $type: collection } }, 287 + { encoding: 'application/json', headers }, 288 + ) 289 + return res.data 290 + } 291 + 292 + async delete( 293 + params: OmitKey<ComAtprotoRepoDeleteRecord.InputSchema, 'collection'>, 294 + headers?: Record<string, string>, 295 + ): Promise<void> { 296 + await this._client.call( 297 + 'com.atproto.repo.deleteRecord', 298 + undefined, 299 + { collection: 'pub.leaflet.publication', ...params }, 300 + { headers }, 301 + ) 302 + } 303 + } 304 + 305 + export class ComNS { 306 + _client: XrpcClient 307 + atproto: ComAtprotoNS 308 + 309 + constructor(client: XrpcClient) { 310 + this._client = client 311 + this.atproto = new ComAtprotoNS(client) 312 + } 313 + } 314 + 315 + export class ComAtprotoNS { 316 + _client: XrpcClient 317 + repo: ComAtprotoRepoNS 318 + 319 + constructor(client: XrpcClient) { 320 + this._client = client 321 + this.repo = new ComAtprotoRepoNS(client) 322 + } 323 + } 324 + 325 + export class ComAtprotoRepoNS { 326 + _client: XrpcClient 327 + 328 + constructor(client: XrpcClient) { 329 + this._client = client 330 + } 331 + 332 + applyWrites( 333 + data?: ComAtprotoRepoApplyWrites.InputSchema, 334 + opts?: ComAtprotoRepoApplyWrites.CallOptions, 335 + ): Promise<ComAtprotoRepoApplyWrites.Response> { 336 + return this._client 337 + .call('com.atproto.repo.applyWrites', opts?.qp, data, opts) 338 + .catch((e) => { 339 + throw ComAtprotoRepoApplyWrites.toKnownErr(e) 340 + }) 341 + } 342 + 343 + createRecord( 344 + data?: ComAtprotoRepoCreateRecord.InputSchema, 345 + opts?: ComAtprotoRepoCreateRecord.CallOptions, 346 + ): Promise<ComAtprotoRepoCreateRecord.Response> { 347 + return this._client 348 + .call('com.atproto.repo.createRecord', opts?.qp, data, opts) 349 + .catch((e) => { 350 + throw ComAtprotoRepoCreateRecord.toKnownErr(e) 351 + }) 352 + } 353 + 354 + deleteRecord( 355 + data?: ComAtprotoRepoDeleteRecord.InputSchema, 356 + opts?: ComAtprotoRepoDeleteRecord.CallOptions, 357 + ): Promise<ComAtprotoRepoDeleteRecord.Response> { 358 + return this._client 359 + .call('com.atproto.repo.deleteRecord', opts?.qp, data, opts) 360 + .catch((e) => { 361 + throw ComAtprotoRepoDeleteRecord.toKnownErr(e) 362 + }) 363 + } 364 + 365 + describeRepo( 366 + params?: ComAtprotoRepoDescribeRepo.QueryParams, 367 + opts?: ComAtprotoRepoDescribeRepo.CallOptions, 368 + ): Promise<ComAtprotoRepoDescribeRepo.Response> { 369 + return this._client.call( 370 + 'com.atproto.repo.describeRepo', 371 + params, 372 + undefined, 373 + opts, 374 + ) 375 + } 376 + 377 + getRecord( 378 + params?: ComAtprotoRepoGetRecord.QueryParams, 379 + opts?: ComAtprotoRepoGetRecord.CallOptions, 380 + ): Promise<ComAtprotoRepoGetRecord.Response> { 381 + return this._client 382 + .call('com.atproto.repo.getRecord', params, undefined, opts) 383 + .catch((e) => { 384 + throw ComAtprotoRepoGetRecord.toKnownErr(e) 385 + }) 386 + } 387 + 388 + importRepo( 389 + data?: ComAtprotoRepoImportRepo.InputSchema, 390 + opts?: ComAtprotoRepoImportRepo.CallOptions, 391 + ): Promise<ComAtprotoRepoImportRepo.Response> { 392 + return this._client.call( 393 + 'com.atproto.repo.importRepo', 394 + opts?.qp, 395 + data, 396 + opts, 397 + ) 398 + } 399 + 400 + listMissingBlobs( 401 + params?: ComAtprotoRepoListMissingBlobs.QueryParams, 402 + opts?: ComAtprotoRepoListMissingBlobs.CallOptions, 403 + ): Promise<ComAtprotoRepoListMissingBlobs.Response> { 404 + return this._client.call( 405 + 'com.atproto.repo.listMissingBlobs', 406 + params, 407 + undefined, 408 + opts, 409 + ) 410 + } 411 + 412 + listRecords( 413 + params?: ComAtprotoRepoListRecords.QueryParams, 414 + opts?: ComAtprotoRepoListRecords.CallOptions, 415 + ): Promise<ComAtprotoRepoListRecords.Response> { 416 + return this._client.call( 417 + 'com.atproto.repo.listRecords', 418 + params, 419 + undefined, 420 + opts, 421 + ) 422 + } 423 + 424 + putRecord( 425 + data?: ComAtprotoRepoPutRecord.InputSchema, 426 + opts?: ComAtprotoRepoPutRecord.CallOptions, 427 + ): Promise<ComAtprotoRepoPutRecord.Response> { 428 + return this._client 429 + .call('com.atproto.repo.putRecord', opts?.qp, data, opts) 430 + .catch((e) => { 431 + throw ComAtprotoRepoPutRecord.toKnownErr(e) 432 + }) 433 + } 434 + 435 + uploadBlob( 436 + data?: ComAtprotoRepoUploadBlob.InputSchema, 437 + opts?: ComAtprotoRepoUploadBlob.CallOptions, 438 + ): Promise<ComAtprotoRepoUploadBlob.Response> { 439 + return this._client.call( 440 + 'com.atproto.repo.uploadBlob', 441 + opts?.qp, 442 + data, 443 + opts, 444 + ) 445 + } 446 + }
+1230
lexicons/src/lexicons.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { 5 + LexiconDoc, 6 + Lexicons, 7 + ValidationError, 8 + ValidationResult, 9 + } from '@atproto/lexicon' 10 + import { $Typed, is$typed, maybe$typed } from './util.js' 11 + 12 + export const schemaDict = { 13 + PubLeafletBlocksHeader: { 14 + lexicon: 1, 15 + id: 'pub.leaflet.blocks.header', 16 + defs: { 17 + main: { 18 + type: 'object', 19 + required: [], 20 + properties: { 21 + level: { 22 + type: 'integer', 23 + minimum: 1, 24 + maximum: 6, 25 + }, 26 + plaintext: { 27 + type: 'string', 28 + }, 29 + }, 30 + }, 31 + }, 32 + }, 33 + PubLeafletBlocksImage: { 34 + lexicon: 1, 35 + id: 'pub.leaflet.blocks.image', 36 + defs: { 37 + main: { 38 + type: 'object', 39 + required: ['image'], 40 + properties: { 41 + image: { 42 + type: 'blob', 43 + accept: ['image/*'], 44 + maxSize: 1000000, 45 + }, 46 + alt: { 47 + type: 'string', 48 + description: 49 + 'Alt text description of the image, for accessibility.', 50 + }, 51 + aspectRatio: { 52 + type: 'ref', 53 + ref: 'lex:pub.leaflet.blocks.image#aspectRatio', 54 + }, 55 + }, 56 + }, 57 + aspectRatio: { 58 + type: 'object', 59 + required: ['width', 'height'], 60 + properties: { 61 + width: { 62 + type: 'integer', 63 + }, 64 + height: { 65 + type: 'integer', 66 + }, 67 + }, 68 + }, 69 + }, 70 + }, 71 + PubLeafletBlocksText: { 72 + lexicon: 1, 73 + id: 'pub.leaflet.blocks.text', 74 + defs: { 75 + main: { 76 + type: 'object', 77 + required: [], 78 + properties: { 79 + plaintext: { 80 + type: 'string', 81 + }, 82 + }, 83 + }, 84 + }, 85 + }, 86 + PubLeafletDocument: { 87 + lexicon: 1, 88 + id: 'pub.leaflet.document', 89 + revision: 1, 90 + description: 'A lexicon for long form rich media documents', 91 + defs: { 92 + main: { 93 + type: 'record', 94 + key: 'tid', 95 + description: 'Record containing a document', 96 + record: { 97 + type: 'object', 98 + required: ['pages', 'author', 'title', 'publication'], 99 + properties: { 100 + title: { 101 + type: 'string', 102 + maxLength: 128, 103 + }, 104 + publishedAt: { 105 + type: 'string', 106 + format: 'datetime', 107 + }, 108 + publication: { 109 + type: 'string', 110 + format: 'at-uri', 111 + }, 112 + author: { 113 + type: 'string', 114 + format: 'at-identifier', 115 + }, 116 + pages: { 117 + type: 'array', 118 + items: { 119 + type: 'union', 120 + refs: ['lex:pub.leaflet.pages.linearDocument'], 121 + }, 122 + }, 123 + }, 124 + }, 125 + }, 126 + }, 127 + }, 128 + PubLeafletPagesLinearDocument: { 129 + lexicon: 1, 130 + id: 'pub.leaflet.pages.linearDocument', 131 + defs: { 132 + main: { 133 + type: 'object', 134 + properties: { 135 + blocks: { 136 + type: 'array', 137 + items: { 138 + type: 'ref', 139 + ref: 'lex:pub.leaflet.pages.linearDocument#block', 140 + }, 141 + }, 142 + }, 143 + }, 144 + block: { 145 + type: 'object', 146 + required: ['block'], 147 + properties: { 148 + block: { 149 + type: 'union', 150 + refs: [ 151 + 'lex:pub.leaflet.blocks.text', 152 + 'lex:pub.leaflet.blocks.header', 153 + 'lex:pub.leaflet.blocks.image', 154 + ], 155 + }, 156 + alignment: { 157 + type: 'string', 158 + knownValues: [ 159 + 'lex:pub.leaflet.pages.linearDocument#textAlignLeft', 160 + 'lex:pub.leaflet.pages.linearDocument#textAlignCenter', 161 + 'lex:pub.leaflet.pages.linearDocument#textAlignRight', 162 + ], 163 + }, 164 + }, 165 + }, 166 + textAlignLeft: { 167 + type: 'token', 168 + }, 169 + textAlignCenter: { 170 + type: 'token', 171 + }, 172 + textAlignRight: { 173 + type: 'token', 174 + }, 175 + }, 176 + }, 177 + PubLeafletPost: { 178 + lexicon: 1, 179 + id: 'pub.leaflet.post', 180 + defs: { 181 + main: { 182 + type: 'record', 183 + key: 'tid', 184 + description: 'Record putting a post in a document', 185 + record: { 186 + type: 'object', 187 + required: ['post', 'publishedAt'], 188 + properties: { 189 + publication: { 190 + type: 'string', 191 + format: 'at-uri', 192 + }, 193 + post: { 194 + type: 'ref', 195 + ref: 'lex:com.atproto.repo.strongRef', 196 + }, 197 + publishedAt: { 198 + type: 'string', 199 + format: 'datetime', 200 + }, 201 + }, 202 + }, 203 + }, 204 + }, 205 + }, 206 + PubLeafletPublication: { 207 + lexicon: 1, 208 + id: 'pub.leaflet.publication', 209 + defs: { 210 + main: { 211 + type: 'record', 212 + key: 'tid', 213 + description: 'Record declaring a publication', 214 + record: { 215 + type: 'object', 216 + required: ['name'], 217 + properties: { 218 + name: { 219 + type: 'string', 220 + maxLength: 2000, 221 + }, 222 + description: { 223 + type: 'string', 224 + maxLength: 2000, 225 + }, 226 + }, 227 + }, 228 + }, 229 + }, 230 + }, 231 + ComAtprotoLabelDefs: { 232 + lexicon: 1, 233 + id: 'com.atproto.label.defs', 234 + defs: { 235 + label: { 236 + type: 'object', 237 + description: 238 + 'Metadata tag on an atproto resource (eg, repo or record).', 239 + required: ['src', 'uri', 'val', 'cts'], 240 + properties: { 241 + ver: { 242 + type: 'integer', 243 + description: 'The AT Protocol version of the label object.', 244 + }, 245 + src: { 246 + type: 'string', 247 + format: 'did', 248 + description: 'DID of the actor who created this label.', 249 + }, 250 + uri: { 251 + type: 'string', 252 + format: 'uri', 253 + description: 254 + 'AT URI of the record, repository (account), or other resource that this label applies to.', 255 + }, 256 + cid: { 257 + type: 'string', 258 + format: 'cid', 259 + description: 260 + "Optionally, CID specifying the specific version of 'uri' resource this label applies to.", 261 + }, 262 + val: { 263 + type: 'string', 264 + maxLength: 128, 265 + description: 266 + 'The short string name of the value or type of this label.', 267 + }, 268 + neg: { 269 + type: 'boolean', 270 + description: 271 + 'If true, this is a negation label, overwriting a previous label.', 272 + }, 273 + cts: { 274 + type: 'string', 275 + format: 'datetime', 276 + description: 'Timestamp when this label was created.', 277 + }, 278 + exp: { 279 + type: 'string', 280 + format: 'datetime', 281 + description: 282 + 'Timestamp at which this label expires (no longer applies).', 283 + }, 284 + sig: { 285 + type: 'bytes', 286 + description: 'Signature of dag-cbor encoded label.', 287 + }, 288 + }, 289 + }, 290 + selfLabels: { 291 + type: 'object', 292 + description: 293 + 'Metadata tags on an atproto record, published by the author within the record.', 294 + required: ['values'], 295 + properties: { 296 + values: { 297 + type: 'array', 298 + items: { 299 + type: 'ref', 300 + ref: 'lex:com.atproto.label.defs#selfLabel', 301 + }, 302 + maxLength: 10, 303 + }, 304 + }, 305 + }, 306 + selfLabel: { 307 + type: 'object', 308 + description: 309 + 'Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.', 310 + required: ['val'], 311 + properties: { 312 + val: { 313 + type: 'string', 314 + maxLength: 128, 315 + description: 316 + 'The short string name of the value or type of this label.', 317 + }, 318 + }, 319 + }, 320 + labelValueDefinition: { 321 + type: 'object', 322 + description: 323 + 'Declares a label value and its expected interpretations and behaviors.', 324 + required: ['identifier', 'severity', 'blurs', 'locales'], 325 + properties: { 326 + identifier: { 327 + type: 'string', 328 + description: 329 + "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).", 330 + maxLength: 100, 331 + maxGraphemes: 100, 332 + }, 333 + severity: { 334 + type: 'string', 335 + description: 336 + "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.", 337 + knownValues: ['inform', 'alert', 'none'], 338 + }, 339 + blurs: { 340 + type: 'string', 341 + description: 342 + "What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing.", 343 + knownValues: ['content', 'media', 'none'], 344 + }, 345 + defaultSetting: { 346 + type: 'string', 347 + description: 'The default setting for this label.', 348 + knownValues: ['ignore', 'warn', 'hide'], 349 + default: 'warn', 350 + }, 351 + adultOnly: { 352 + type: 'boolean', 353 + description: 354 + 'Does the user need to have adult content enabled in order to configure this label?', 355 + }, 356 + locales: { 357 + type: 'array', 358 + items: { 359 + type: 'ref', 360 + ref: 'lex:com.atproto.label.defs#labelValueDefinitionStrings', 361 + }, 362 + }, 363 + }, 364 + }, 365 + labelValueDefinitionStrings: { 366 + type: 'object', 367 + description: 368 + 'Strings which describe the label in the UI, localized into a specific language.', 369 + required: ['lang', 'name', 'description'], 370 + properties: { 371 + lang: { 372 + type: 'string', 373 + description: 374 + 'The code of the language these strings are written in.', 375 + format: 'language', 376 + }, 377 + name: { 378 + type: 'string', 379 + description: 'A short human-readable name for the label.', 380 + maxGraphemes: 64, 381 + maxLength: 640, 382 + }, 383 + description: { 384 + type: 'string', 385 + description: 386 + 'A longer description of what the label means and why it might be applied.', 387 + maxGraphemes: 10000, 388 + maxLength: 100000, 389 + }, 390 + }, 391 + }, 392 + labelValue: { 393 + type: 'string', 394 + knownValues: [ 395 + '!hide', 396 + '!no-promote', 397 + '!warn', 398 + '!no-unauthenticated', 399 + 'dmca-violation', 400 + 'doxxing', 401 + 'porn', 402 + 'sexual', 403 + 'nudity', 404 + 'nsfl', 405 + 'gore', 406 + ], 407 + }, 408 + }, 409 + }, 410 + ComAtprotoRepoApplyWrites: { 411 + lexicon: 1, 412 + id: 'com.atproto.repo.applyWrites', 413 + defs: { 414 + main: { 415 + type: 'procedure', 416 + description: 417 + 'Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.', 418 + input: { 419 + encoding: 'application/json', 420 + schema: { 421 + type: 'object', 422 + required: ['repo', 'writes'], 423 + properties: { 424 + repo: { 425 + type: 'string', 426 + format: 'at-identifier', 427 + description: 428 + 'The handle or DID of the repo (aka, current account).', 429 + }, 430 + validate: { 431 + type: 'boolean', 432 + description: 433 + "Can be set to 'false' to skip Lexicon schema validation of record data across all operations, 'true' to require it, or leave unset to validate only for known Lexicons.", 434 + }, 435 + writes: { 436 + type: 'array', 437 + items: { 438 + type: 'union', 439 + refs: [ 440 + 'lex:com.atproto.repo.applyWrites#create', 441 + 'lex:com.atproto.repo.applyWrites#update', 442 + 'lex:com.atproto.repo.applyWrites#delete', 443 + ], 444 + closed: true, 445 + }, 446 + }, 447 + swapCommit: { 448 + type: 'string', 449 + description: 450 + 'If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.', 451 + format: 'cid', 452 + }, 453 + }, 454 + }, 455 + }, 456 + output: { 457 + encoding: 'application/json', 458 + schema: { 459 + type: 'object', 460 + required: [], 461 + properties: { 462 + commit: { 463 + type: 'ref', 464 + ref: 'lex:com.atproto.repo.defs#commitMeta', 465 + }, 466 + results: { 467 + type: 'array', 468 + items: { 469 + type: 'union', 470 + refs: [ 471 + 'lex:com.atproto.repo.applyWrites#createResult', 472 + 'lex:com.atproto.repo.applyWrites#updateResult', 473 + 'lex:com.atproto.repo.applyWrites#deleteResult', 474 + ], 475 + closed: true, 476 + }, 477 + }, 478 + }, 479 + }, 480 + }, 481 + errors: [ 482 + { 483 + name: 'InvalidSwap', 484 + description: 485 + "Indicates that the 'swapCommit' parameter did not match current commit.", 486 + }, 487 + ], 488 + }, 489 + create: { 490 + type: 'object', 491 + description: 'Operation which creates a new record.', 492 + required: ['collection', 'value'], 493 + properties: { 494 + collection: { 495 + type: 'string', 496 + format: 'nsid', 497 + }, 498 + rkey: { 499 + type: 'string', 500 + maxLength: 512, 501 + format: 'record-key', 502 + description: 503 + 'NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility.', 504 + }, 505 + value: { 506 + type: 'unknown', 507 + }, 508 + }, 509 + }, 510 + update: { 511 + type: 'object', 512 + description: 'Operation which updates an existing record.', 513 + required: ['collection', 'rkey', 'value'], 514 + properties: { 515 + collection: { 516 + type: 'string', 517 + format: 'nsid', 518 + }, 519 + rkey: { 520 + type: 'string', 521 + format: 'record-key', 522 + }, 523 + value: { 524 + type: 'unknown', 525 + }, 526 + }, 527 + }, 528 + delete: { 529 + type: 'object', 530 + description: 'Operation which deletes an existing record.', 531 + required: ['collection', 'rkey'], 532 + properties: { 533 + collection: { 534 + type: 'string', 535 + format: 'nsid', 536 + }, 537 + rkey: { 538 + type: 'string', 539 + format: 'record-key', 540 + }, 541 + }, 542 + }, 543 + createResult: { 544 + type: 'object', 545 + required: ['uri', 'cid'], 546 + properties: { 547 + uri: { 548 + type: 'string', 549 + format: 'at-uri', 550 + }, 551 + cid: { 552 + type: 'string', 553 + format: 'cid', 554 + }, 555 + validationStatus: { 556 + type: 'string', 557 + knownValues: ['valid', 'unknown'], 558 + }, 559 + }, 560 + }, 561 + updateResult: { 562 + type: 'object', 563 + required: ['uri', 'cid'], 564 + properties: { 565 + uri: { 566 + type: 'string', 567 + format: 'at-uri', 568 + }, 569 + cid: { 570 + type: 'string', 571 + format: 'cid', 572 + }, 573 + validationStatus: { 574 + type: 'string', 575 + knownValues: ['valid', 'unknown'], 576 + }, 577 + }, 578 + }, 579 + deleteResult: { 580 + type: 'object', 581 + required: [], 582 + properties: {}, 583 + }, 584 + }, 585 + }, 586 + ComAtprotoRepoCreateRecord: { 587 + lexicon: 1, 588 + id: 'com.atproto.repo.createRecord', 589 + defs: { 590 + main: { 591 + type: 'procedure', 592 + description: 593 + 'Create a single new repository record. Requires auth, implemented by PDS.', 594 + input: { 595 + encoding: 'application/json', 596 + schema: { 597 + type: 'object', 598 + required: ['repo', 'collection', 'record'], 599 + properties: { 600 + repo: { 601 + type: 'string', 602 + format: 'at-identifier', 603 + description: 604 + 'The handle or DID of the repo (aka, current account).', 605 + }, 606 + collection: { 607 + type: 'string', 608 + format: 'nsid', 609 + description: 'The NSID of the record collection.', 610 + }, 611 + rkey: { 612 + type: 'string', 613 + format: 'record-key', 614 + description: 'The Record Key.', 615 + maxLength: 512, 616 + }, 617 + validate: { 618 + type: 'boolean', 619 + description: 620 + "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons.", 621 + }, 622 + record: { 623 + type: 'unknown', 624 + description: 'The record itself. Must contain a $type field.', 625 + }, 626 + swapCommit: { 627 + type: 'string', 628 + format: 'cid', 629 + description: 630 + 'Compare and swap with the previous commit by CID.', 631 + }, 632 + }, 633 + }, 634 + }, 635 + output: { 636 + encoding: 'application/json', 637 + schema: { 638 + type: 'object', 639 + required: ['uri', 'cid'], 640 + properties: { 641 + uri: { 642 + type: 'string', 643 + format: 'at-uri', 644 + }, 645 + cid: { 646 + type: 'string', 647 + format: 'cid', 648 + }, 649 + commit: { 650 + type: 'ref', 651 + ref: 'lex:com.atproto.repo.defs#commitMeta', 652 + }, 653 + validationStatus: { 654 + type: 'string', 655 + knownValues: ['valid', 'unknown'], 656 + }, 657 + }, 658 + }, 659 + }, 660 + errors: [ 661 + { 662 + name: 'InvalidSwap', 663 + description: 664 + "Indicates that 'swapCommit' didn't match current repo commit.", 665 + }, 666 + ], 667 + }, 668 + }, 669 + }, 670 + ComAtprotoRepoDefs: { 671 + lexicon: 1, 672 + id: 'com.atproto.repo.defs', 673 + defs: { 674 + commitMeta: { 675 + type: 'object', 676 + required: ['cid', 'rev'], 677 + properties: { 678 + cid: { 679 + type: 'string', 680 + format: 'cid', 681 + }, 682 + rev: { 683 + type: 'string', 684 + format: 'tid', 685 + }, 686 + }, 687 + }, 688 + }, 689 + }, 690 + ComAtprotoRepoDeleteRecord: { 691 + lexicon: 1, 692 + id: 'com.atproto.repo.deleteRecord', 693 + defs: { 694 + main: { 695 + type: 'procedure', 696 + description: 697 + "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", 698 + input: { 699 + encoding: 'application/json', 700 + schema: { 701 + type: 'object', 702 + required: ['repo', 'collection', 'rkey'], 703 + properties: { 704 + repo: { 705 + type: 'string', 706 + format: 'at-identifier', 707 + description: 708 + 'The handle or DID of the repo (aka, current account).', 709 + }, 710 + collection: { 711 + type: 'string', 712 + format: 'nsid', 713 + description: 'The NSID of the record collection.', 714 + }, 715 + rkey: { 716 + type: 'string', 717 + format: 'record-key', 718 + description: 'The Record Key.', 719 + }, 720 + swapRecord: { 721 + type: 'string', 722 + format: 'cid', 723 + description: 724 + 'Compare and swap with the previous record by CID.', 725 + }, 726 + swapCommit: { 727 + type: 'string', 728 + format: 'cid', 729 + description: 730 + 'Compare and swap with the previous commit by CID.', 731 + }, 732 + }, 733 + }, 734 + }, 735 + output: { 736 + encoding: 'application/json', 737 + schema: { 738 + type: 'object', 739 + properties: { 740 + commit: { 741 + type: 'ref', 742 + ref: 'lex:com.atproto.repo.defs#commitMeta', 743 + }, 744 + }, 745 + }, 746 + }, 747 + errors: [ 748 + { 749 + name: 'InvalidSwap', 750 + }, 751 + ], 752 + }, 753 + }, 754 + }, 755 + ComAtprotoRepoDescribeRepo: { 756 + lexicon: 1, 757 + id: 'com.atproto.repo.describeRepo', 758 + defs: { 759 + main: { 760 + type: 'query', 761 + description: 762 + 'Get information about an account and repository, including the list of collections. Does not require auth.', 763 + parameters: { 764 + type: 'params', 765 + required: ['repo'], 766 + properties: { 767 + repo: { 768 + type: 'string', 769 + format: 'at-identifier', 770 + description: 'The handle or DID of the repo.', 771 + }, 772 + }, 773 + }, 774 + output: { 775 + encoding: 'application/json', 776 + schema: { 777 + type: 'object', 778 + required: [ 779 + 'handle', 780 + 'did', 781 + 'didDoc', 782 + 'collections', 783 + 'handleIsCorrect', 784 + ], 785 + properties: { 786 + handle: { 787 + type: 'string', 788 + format: 'handle', 789 + }, 790 + did: { 791 + type: 'string', 792 + format: 'did', 793 + }, 794 + didDoc: { 795 + type: 'unknown', 796 + description: 'The complete DID document for this account.', 797 + }, 798 + collections: { 799 + type: 'array', 800 + description: 801 + 'List of all the collections (NSIDs) for which this repo contains at least one record.', 802 + items: { 803 + type: 'string', 804 + format: 'nsid', 805 + }, 806 + }, 807 + handleIsCorrect: { 808 + type: 'boolean', 809 + description: 810 + 'Indicates if handle is currently valid (resolves bi-directionally)', 811 + }, 812 + }, 813 + }, 814 + }, 815 + }, 816 + }, 817 + }, 818 + ComAtprotoRepoGetRecord: { 819 + lexicon: 1, 820 + id: 'com.atproto.repo.getRecord', 821 + defs: { 822 + main: { 823 + type: 'query', 824 + description: 825 + 'Get a single record from a repository. Does not require auth.', 826 + parameters: { 827 + type: 'params', 828 + required: ['repo', 'collection', 'rkey'], 829 + properties: { 830 + repo: { 831 + type: 'string', 832 + format: 'at-identifier', 833 + description: 'The handle or DID of the repo.', 834 + }, 835 + collection: { 836 + type: 'string', 837 + format: 'nsid', 838 + description: 'The NSID of the record collection.', 839 + }, 840 + rkey: { 841 + type: 'string', 842 + description: 'The Record Key.', 843 + format: 'record-key', 844 + }, 845 + cid: { 846 + type: 'string', 847 + format: 'cid', 848 + description: 849 + 'The CID of the version of the record. If not specified, then return the most recent version.', 850 + }, 851 + }, 852 + }, 853 + output: { 854 + encoding: 'application/json', 855 + schema: { 856 + type: 'object', 857 + required: ['uri', 'value'], 858 + properties: { 859 + uri: { 860 + type: 'string', 861 + format: 'at-uri', 862 + }, 863 + cid: { 864 + type: 'string', 865 + format: 'cid', 866 + }, 867 + value: { 868 + type: 'unknown', 869 + }, 870 + }, 871 + }, 872 + }, 873 + errors: [ 874 + { 875 + name: 'RecordNotFound', 876 + }, 877 + ], 878 + }, 879 + }, 880 + }, 881 + ComAtprotoRepoImportRepo: { 882 + lexicon: 1, 883 + id: 'com.atproto.repo.importRepo', 884 + defs: { 885 + main: { 886 + type: 'procedure', 887 + description: 888 + 'Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.', 889 + input: { 890 + encoding: 'application/vnd.ipld.car', 891 + }, 892 + }, 893 + }, 894 + }, 895 + ComAtprotoRepoListMissingBlobs: { 896 + lexicon: 1, 897 + id: 'com.atproto.repo.listMissingBlobs', 898 + defs: { 899 + main: { 900 + type: 'query', 901 + description: 902 + 'Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.', 903 + parameters: { 904 + type: 'params', 905 + properties: { 906 + limit: { 907 + type: 'integer', 908 + minimum: 1, 909 + maximum: 1000, 910 + default: 500, 911 + }, 912 + cursor: { 913 + type: 'string', 914 + }, 915 + }, 916 + }, 917 + output: { 918 + encoding: 'application/json', 919 + schema: { 920 + type: 'object', 921 + required: ['blobs'], 922 + properties: { 923 + cursor: { 924 + type: 'string', 925 + }, 926 + blobs: { 927 + type: 'array', 928 + items: { 929 + type: 'ref', 930 + ref: 'lex:com.atproto.repo.listMissingBlobs#recordBlob', 931 + }, 932 + }, 933 + }, 934 + }, 935 + }, 936 + }, 937 + recordBlob: { 938 + type: 'object', 939 + required: ['cid', 'recordUri'], 940 + properties: { 941 + cid: { 942 + type: 'string', 943 + format: 'cid', 944 + }, 945 + recordUri: { 946 + type: 'string', 947 + format: 'at-uri', 948 + }, 949 + }, 950 + }, 951 + }, 952 + }, 953 + ComAtprotoRepoListRecords: { 954 + lexicon: 1, 955 + id: 'com.atproto.repo.listRecords', 956 + defs: { 957 + main: { 958 + type: 'query', 959 + description: 960 + 'List a range of records in a repository, matching a specific collection. Does not require auth.', 961 + parameters: { 962 + type: 'params', 963 + required: ['repo', 'collection'], 964 + properties: { 965 + repo: { 966 + type: 'string', 967 + format: 'at-identifier', 968 + description: 'The handle or DID of the repo.', 969 + }, 970 + collection: { 971 + type: 'string', 972 + format: 'nsid', 973 + description: 'The NSID of the record type.', 974 + }, 975 + limit: { 976 + type: 'integer', 977 + minimum: 1, 978 + maximum: 100, 979 + default: 50, 980 + description: 'The number of records to return.', 981 + }, 982 + cursor: { 983 + type: 'string', 984 + }, 985 + rkeyStart: { 986 + type: 'string', 987 + description: 988 + 'DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)', 989 + }, 990 + rkeyEnd: { 991 + type: 'string', 992 + description: 993 + 'DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)', 994 + }, 995 + reverse: { 996 + type: 'boolean', 997 + description: 'Flag to reverse the order of the returned records.', 998 + }, 999 + }, 1000 + }, 1001 + output: { 1002 + encoding: 'application/json', 1003 + schema: { 1004 + type: 'object', 1005 + required: ['records'], 1006 + properties: { 1007 + cursor: { 1008 + type: 'string', 1009 + }, 1010 + records: { 1011 + type: 'array', 1012 + items: { 1013 + type: 'ref', 1014 + ref: 'lex:com.atproto.repo.listRecords#record', 1015 + }, 1016 + }, 1017 + }, 1018 + }, 1019 + }, 1020 + }, 1021 + record: { 1022 + type: 'object', 1023 + required: ['uri', 'cid', 'value'], 1024 + properties: { 1025 + uri: { 1026 + type: 'string', 1027 + format: 'at-uri', 1028 + }, 1029 + cid: { 1030 + type: 'string', 1031 + format: 'cid', 1032 + }, 1033 + value: { 1034 + type: 'unknown', 1035 + }, 1036 + }, 1037 + }, 1038 + }, 1039 + }, 1040 + ComAtprotoRepoPutRecord: { 1041 + lexicon: 1, 1042 + id: 'com.atproto.repo.putRecord', 1043 + defs: { 1044 + main: { 1045 + type: 'procedure', 1046 + description: 1047 + 'Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.', 1048 + input: { 1049 + encoding: 'application/json', 1050 + schema: { 1051 + type: 'object', 1052 + required: ['repo', 'collection', 'rkey', 'record'], 1053 + nullable: ['swapRecord'], 1054 + properties: { 1055 + repo: { 1056 + type: 'string', 1057 + format: 'at-identifier', 1058 + description: 1059 + 'The handle or DID of the repo (aka, current account).', 1060 + }, 1061 + collection: { 1062 + type: 'string', 1063 + format: 'nsid', 1064 + description: 'The NSID of the record collection.', 1065 + }, 1066 + rkey: { 1067 + type: 'string', 1068 + format: 'record-key', 1069 + description: 'The Record Key.', 1070 + maxLength: 512, 1071 + }, 1072 + validate: { 1073 + type: 'boolean', 1074 + description: 1075 + "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons.", 1076 + }, 1077 + record: { 1078 + type: 'unknown', 1079 + description: 'The record to write.', 1080 + }, 1081 + swapRecord: { 1082 + type: 'string', 1083 + format: 'cid', 1084 + description: 1085 + 'Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation', 1086 + }, 1087 + swapCommit: { 1088 + type: 'string', 1089 + format: 'cid', 1090 + description: 1091 + 'Compare and swap with the previous commit by CID.', 1092 + }, 1093 + }, 1094 + }, 1095 + }, 1096 + output: { 1097 + encoding: 'application/json', 1098 + schema: { 1099 + type: 'object', 1100 + required: ['uri', 'cid'], 1101 + properties: { 1102 + uri: { 1103 + type: 'string', 1104 + format: 'at-uri', 1105 + }, 1106 + cid: { 1107 + type: 'string', 1108 + format: 'cid', 1109 + }, 1110 + commit: { 1111 + type: 'ref', 1112 + ref: 'lex:com.atproto.repo.defs#commitMeta', 1113 + }, 1114 + validationStatus: { 1115 + type: 'string', 1116 + knownValues: ['valid', 'unknown'], 1117 + }, 1118 + }, 1119 + }, 1120 + }, 1121 + errors: [ 1122 + { 1123 + name: 'InvalidSwap', 1124 + }, 1125 + ], 1126 + }, 1127 + }, 1128 + }, 1129 + ComAtprotoRepoStrongRef: { 1130 + lexicon: 1, 1131 + id: 'com.atproto.repo.strongRef', 1132 + description: 'A URI with a content-hash fingerprint.', 1133 + defs: { 1134 + main: { 1135 + type: 'object', 1136 + required: ['uri', 'cid'], 1137 + properties: { 1138 + uri: { 1139 + type: 'string', 1140 + format: 'at-uri', 1141 + }, 1142 + cid: { 1143 + type: 'string', 1144 + format: 'cid', 1145 + }, 1146 + }, 1147 + }, 1148 + }, 1149 + }, 1150 + ComAtprotoRepoUploadBlob: { 1151 + lexicon: 1, 1152 + id: 'com.atproto.repo.uploadBlob', 1153 + defs: { 1154 + main: { 1155 + type: 'procedure', 1156 + description: 1157 + 'Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.', 1158 + input: { 1159 + encoding: '*/*', 1160 + }, 1161 + output: { 1162 + encoding: 'application/json', 1163 + schema: { 1164 + type: 'object', 1165 + required: ['blob'], 1166 + properties: { 1167 + blob: { 1168 + type: 'blob', 1169 + }, 1170 + }, 1171 + }, 1172 + }, 1173 + }, 1174 + }, 1175 + }, 1176 + } as const satisfies Record<string, LexiconDoc> 1177 + 1178 + export const schemas = Object.values(schemaDict) satisfies LexiconDoc[] 1179 + export const lexicons: Lexicons = new Lexicons(schemas) 1180 + 1181 + export function validate<T extends { $type: string }>( 1182 + v: unknown, 1183 + id: string, 1184 + hash: string, 1185 + requiredType: true, 1186 + ): ValidationResult<T> 1187 + export function validate<T extends { $type?: string }>( 1188 + v: unknown, 1189 + id: string, 1190 + hash: string, 1191 + requiredType?: false, 1192 + ): ValidationResult<T> 1193 + export function validate( 1194 + v: unknown, 1195 + id: string, 1196 + hash: string, 1197 + requiredType?: boolean, 1198 + ): ValidationResult { 1199 + return (requiredType ? is$typed : maybe$typed)(v, id, hash) 1200 + ? lexicons.validate(`${id}#${hash}`, v) 1201 + : { 1202 + success: false, 1203 + error: new ValidationError( 1204 + `Must be an object with "${hash === 'main' ? id : `${id}#${hash}`}" $type property`, 1205 + ), 1206 + } 1207 + } 1208 + 1209 + export const ids = { 1210 + PubLeafletBlocksHeader: 'pub.leaflet.blocks.header', 1211 + PubLeafletBlocksImage: 'pub.leaflet.blocks.image', 1212 + PubLeafletBlocksText: 'pub.leaflet.blocks.text', 1213 + PubLeafletDocument: 'pub.leaflet.document', 1214 + PubLeafletPagesLinearDocument: 'pub.leaflet.pages.linearDocument', 1215 + PubLeafletPost: 'pub.leaflet.post', 1216 + PubLeafletPublication: 'pub.leaflet.publication', 1217 + ComAtprotoLabelDefs: 'com.atproto.label.defs', 1218 + ComAtprotoRepoApplyWrites: 'com.atproto.repo.applyWrites', 1219 + ComAtprotoRepoCreateRecord: 'com.atproto.repo.createRecord', 1220 + ComAtprotoRepoDefs: 'com.atproto.repo.defs', 1221 + ComAtprotoRepoDeleteRecord: 'com.atproto.repo.deleteRecord', 1222 + ComAtprotoRepoDescribeRepo: 'com.atproto.repo.describeRepo', 1223 + ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord', 1224 + ComAtprotoRepoImportRepo: 'com.atproto.repo.importRepo', 1225 + ComAtprotoRepoListMissingBlobs: 'com.atproto.repo.listMissingBlobs', 1226 + ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords', 1227 + ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord', 1228 + ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', 1229 + ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob', 1230 + } as const
+142
lexicons/src/types/com/atproto/label/defs.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'com.atproto.label.defs' 12 + 13 + /** Metadata tag on an atproto resource (eg, repo or record). */ 14 + export interface Label { 15 + $type?: 'com.atproto.label.defs#label' 16 + /** The AT Protocol version of the label object. */ 17 + ver?: number 18 + /** DID of the actor who created this label. */ 19 + src: string 20 + /** AT URI of the record, repository (account), or other resource that this label applies to. */ 21 + uri: string 22 + /** Optionally, CID specifying the specific version of 'uri' resource this label applies to. */ 23 + cid?: string 24 + /** The short string name of the value or type of this label. */ 25 + val: string 26 + /** If true, this is a negation label, overwriting a previous label. */ 27 + neg?: boolean 28 + /** Timestamp when this label was created. */ 29 + cts: string 30 + /** Timestamp at which this label expires (no longer applies). */ 31 + exp?: string 32 + /** Signature of dag-cbor encoded label. */ 33 + sig?: Uint8Array 34 + } 35 + 36 + const hashLabel = 'label' 37 + 38 + export function isLabel<V>(v: V) { 39 + return is$typed(v, id, hashLabel) 40 + } 41 + 42 + export function validateLabel<V>(v: V) { 43 + return validate<Label & V>(v, id, hashLabel) 44 + } 45 + 46 + /** Metadata tags on an atproto record, published by the author within the record. */ 47 + export interface SelfLabels { 48 + $type?: 'com.atproto.label.defs#selfLabels' 49 + values: SelfLabel[] 50 + } 51 + 52 + const hashSelfLabels = 'selfLabels' 53 + 54 + export function isSelfLabels<V>(v: V) { 55 + return is$typed(v, id, hashSelfLabels) 56 + } 57 + 58 + export function validateSelfLabels<V>(v: V) { 59 + return validate<SelfLabels & V>(v, id, hashSelfLabels) 60 + } 61 + 62 + /** Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel. */ 63 + export interface SelfLabel { 64 + $type?: 'com.atproto.label.defs#selfLabel' 65 + /** The short string name of the value or type of this label. */ 66 + val: string 67 + } 68 + 69 + const hashSelfLabel = 'selfLabel' 70 + 71 + export function isSelfLabel<V>(v: V) { 72 + return is$typed(v, id, hashSelfLabel) 73 + } 74 + 75 + export function validateSelfLabel<V>(v: V) { 76 + return validate<SelfLabel & V>(v, id, hashSelfLabel) 77 + } 78 + 79 + /** Declares a label value and its expected interpretations and behaviors. */ 80 + export interface LabelValueDefinition { 81 + $type?: 'com.atproto.label.defs#labelValueDefinition' 82 + /** The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+). */ 83 + identifier: string 84 + /** How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing. */ 85 + severity: 'inform' | 'alert' | 'none' | (string & {}) 86 + /** What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing. */ 87 + blurs: 'content' | 'media' | 'none' | (string & {}) 88 + /** The default setting for this label. */ 89 + defaultSetting: 'ignore' | 'warn' | 'hide' | (string & {}) 90 + /** Does the user need to have adult content enabled in order to configure this label? */ 91 + adultOnly?: boolean 92 + locales: LabelValueDefinitionStrings[] 93 + } 94 + 95 + const hashLabelValueDefinition = 'labelValueDefinition' 96 + 97 + export function isLabelValueDefinition<V>(v: V) { 98 + return is$typed(v, id, hashLabelValueDefinition) 99 + } 100 + 101 + export function validateLabelValueDefinition<V>(v: V) { 102 + return validate<LabelValueDefinition & V>(v, id, hashLabelValueDefinition) 103 + } 104 + 105 + /** Strings which describe the label in the UI, localized into a specific language. */ 106 + export interface LabelValueDefinitionStrings { 107 + $type?: 'com.atproto.label.defs#labelValueDefinitionStrings' 108 + /** The code of the language these strings are written in. */ 109 + lang: string 110 + /** A short human-readable name for the label. */ 111 + name: string 112 + /** A longer description of what the label means and why it might be applied. */ 113 + description: string 114 + } 115 + 116 + const hashLabelValueDefinitionStrings = 'labelValueDefinitionStrings' 117 + 118 + export function isLabelValueDefinitionStrings<V>(v: V) { 119 + return is$typed(v, id, hashLabelValueDefinitionStrings) 120 + } 121 + 122 + export function validateLabelValueDefinitionStrings<V>(v: V) { 123 + return validate<LabelValueDefinitionStrings & V>( 124 + v, 125 + id, 126 + hashLabelValueDefinitionStrings, 127 + ) 128 + } 129 + 130 + export type LabelValue = 131 + | '!hide' 132 + | '!no-promote' 133 + | '!warn' 134 + | '!no-unauthenticated' 135 + | 'dmca-violation' 136 + | 'doxxing' 137 + | 'porn' 138 + | 'sexual' 139 + | 'nudity' 140 + | 'nsfl' 141 + | 'gore' 142 + | (string & {})
+163
lexicons/src/types/com/atproto/repo/applyWrites.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + import type * as ComAtprotoRepoDefs from './defs.js' 10 + 11 + const is$typed = _is$typed, 12 + validate = _validate 13 + const id = 'com.atproto.repo.applyWrites' 14 + 15 + export interface QueryParams {} 16 + 17 + export interface InputSchema { 18 + /** The handle or DID of the repo (aka, current account). */ 19 + repo: string 20 + /** Can be set to 'false' to skip Lexicon schema validation of record data across all operations, 'true' to require it, or leave unset to validate only for known Lexicons. */ 21 + validate?: boolean 22 + writes: ($Typed<Create> | $Typed<Update> | $Typed<Delete>)[] 23 + /** If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations. */ 24 + swapCommit?: string 25 + } 26 + 27 + export interface OutputSchema { 28 + commit?: ComAtprotoRepoDefs.CommitMeta 29 + results?: ( 30 + | $Typed<CreateResult> 31 + | $Typed<UpdateResult> 32 + | $Typed<DeleteResult> 33 + )[] 34 + } 35 + 36 + export interface CallOptions { 37 + signal?: AbortSignal 38 + headers?: HeadersMap 39 + qp?: QueryParams 40 + encoding?: 'application/json' 41 + } 42 + 43 + export interface Response { 44 + success: boolean 45 + headers: HeadersMap 46 + data: OutputSchema 47 + } 48 + 49 + export class InvalidSwapError extends XRPCError { 50 + constructor(src: XRPCError) { 51 + super(src.status, src.error, src.message, src.headers, { cause: src }) 52 + } 53 + } 54 + 55 + export function toKnownErr(e: any) { 56 + if (e instanceof XRPCError) { 57 + if (e.error === 'InvalidSwap') return new InvalidSwapError(e) 58 + } 59 + 60 + return e 61 + } 62 + 63 + /** Operation which creates a new record. */ 64 + export interface Create { 65 + $type?: 'com.atproto.repo.applyWrites#create' 66 + collection: string 67 + /** NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility. */ 68 + rkey?: string 69 + value: { [_ in string]: unknown } 70 + } 71 + 72 + const hashCreate = 'create' 73 + 74 + export function isCreate<V>(v: V) { 75 + return is$typed(v, id, hashCreate) 76 + } 77 + 78 + export function validateCreate<V>(v: V) { 79 + return validate<Create & V>(v, id, hashCreate) 80 + } 81 + 82 + /** Operation which updates an existing record. */ 83 + export interface Update { 84 + $type?: 'com.atproto.repo.applyWrites#update' 85 + collection: string 86 + rkey: string 87 + value: { [_ in string]: unknown } 88 + } 89 + 90 + const hashUpdate = 'update' 91 + 92 + export function isUpdate<V>(v: V) { 93 + return is$typed(v, id, hashUpdate) 94 + } 95 + 96 + export function validateUpdate<V>(v: V) { 97 + return validate<Update & V>(v, id, hashUpdate) 98 + } 99 + 100 + /** Operation which deletes an existing record. */ 101 + export interface Delete { 102 + $type?: 'com.atproto.repo.applyWrites#delete' 103 + collection: string 104 + rkey: string 105 + } 106 + 107 + const hashDelete = 'delete' 108 + 109 + export function isDelete<V>(v: V) { 110 + return is$typed(v, id, hashDelete) 111 + } 112 + 113 + export function validateDelete<V>(v: V) { 114 + return validate<Delete & V>(v, id, hashDelete) 115 + } 116 + 117 + export interface CreateResult { 118 + $type?: 'com.atproto.repo.applyWrites#createResult' 119 + uri: string 120 + cid: string 121 + validationStatus?: 'valid' | 'unknown' | (string & {}) 122 + } 123 + 124 + const hashCreateResult = 'createResult' 125 + 126 + export function isCreateResult<V>(v: V) { 127 + return is$typed(v, id, hashCreateResult) 128 + } 129 + 130 + export function validateCreateResult<V>(v: V) { 131 + return validate<CreateResult & V>(v, id, hashCreateResult) 132 + } 133 + 134 + export interface UpdateResult { 135 + $type?: 'com.atproto.repo.applyWrites#updateResult' 136 + uri: string 137 + cid: string 138 + validationStatus?: 'valid' | 'unknown' | (string & {}) 139 + } 140 + 141 + const hashUpdateResult = 'updateResult' 142 + 143 + export function isUpdateResult<V>(v: V) { 144 + return is$typed(v, id, hashUpdateResult) 145 + } 146 + 147 + export function validateUpdateResult<V>(v: V) { 148 + return validate<UpdateResult & V>(v, id, hashUpdateResult) 149 + } 150 + 151 + export interface DeleteResult { 152 + $type?: 'com.atproto.repo.applyWrites#deleteResult' 153 + } 154 + 155 + const hashDeleteResult = 'deleteResult' 156 + 157 + export function isDeleteResult<V>(v: V) { 158 + return is$typed(v, id, hashDeleteResult) 159 + } 160 + 161 + export function validateDeleteResult<V>(v: V) { 162 + return validate<DeleteResult & V>(v, id, hashDeleteResult) 163 + }
+64
lexicons/src/types/com/atproto/repo/createRecord.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + import type * as ComAtprotoRepoDefs from './defs.js' 10 + 11 + const is$typed = _is$typed, 12 + validate = _validate 13 + const id = 'com.atproto.repo.createRecord' 14 + 15 + export interface QueryParams {} 16 + 17 + export interface InputSchema { 18 + /** The handle or DID of the repo (aka, current account). */ 19 + repo: string 20 + /** The NSID of the record collection. */ 21 + collection: string 22 + /** The Record Key. */ 23 + rkey?: string 24 + /** Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons. */ 25 + validate?: boolean 26 + /** The record itself. Must contain a $type field. */ 27 + record: { [_ in string]: unknown } 28 + /** Compare and swap with the previous commit by CID. */ 29 + swapCommit?: string 30 + } 31 + 32 + export interface OutputSchema { 33 + uri: string 34 + cid: string 35 + commit?: ComAtprotoRepoDefs.CommitMeta 36 + validationStatus?: 'valid' | 'unknown' | (string & {}) 37 + } 38 + 39 + export interface CallOptions { 40 + signal?: AbortSignal 41 + headers?: HeadersMap 42 + qp?: QueryParams 43 + encoding?: 'application/json' 44 + } 45 + 46 + export interface Response { 47 + success: boolean 48 + headers: HeadersMap 49 + data: OutputSchema 50 + } 51 + 52 + export class InvalidSwapError extends XRPCError { 53 + constructor(src: XRPCError) { 54 + super(src.status, src.error, src.message, src.headers, { cause: src }) 55 + } 56 + } 57 + 58 + export function toKnownErr(e: any) { 59 + if (e instanceof XRPCError) { 60 + if (e.error === 'InvalidSwap') return new InvalidSwapError(e) 61 + } 62 + 63 + return e 64 + }
+27
lexicons/src/types/com/atproto/repo/defs.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'com.atproto.repo.defs' 12 + 13 + export interface CommitMeta { 14 + $type?: 'com.atproto.repo.defs#commitMeta' 15 + cid: string 16 + rev: string 17 + } 18 + 19 + const hashCommitMeta = 'commitMeta' 20 + 21 + export function isCommitMeta<V>(v: V) { 22 + return is$typed(v, id, hashCommitMeta) 23 + } 24 + 25 + export function validateCommitMeta<V>(v: V) { 26 + return validate<CommitMeta & V>(v, id, hashCommitMeta) 27 + }
+59
lexicons/src/types/com/atproto/repo/deleteRecord.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + import type * as ComAtprotoRepoDefs from './defs.js' 10 + 11 + const is$typed = _is$typed, 12 + validate = _validate 13 + const id = 'com.atproto.repo.deleteRecord' 14 + 15 + export interface QueryParams {} 16 + 17 + export interface InputSchema { 18 + /** The handle or DID of the repo (aka, current account). */ 19 + repo: string 20 + /** The NSID of the record collection. */ 21 + collection: string 22 + /** The Record Key. */ 23 + rkey: string 24 + /** Compare and swap with the previous record by CID. */ 25 + swapRecord?: string 26 + /** Compare and swap with the previous commit by CID. */ 27 + swapCommit?: string 28 + } 29 + 30 + export interface OutputSchema { 31 + commit?: ComAtprotoRepoDefs.CommitMeta 32 + } 33 + 34 + export interface CallOptions { 35 + signal?: AbortSignal 36 + headers?: HeadersMap 37 + qp?: QueryParams 38 + encoding?: 'application/json' 39 + } 40 + 41 + export interface Response { 42 + success: boolean 43 + headers: HeadersMap 44 + data: OutputSchema 45 + } 46 + 47 + export class InvalidSwapError extends XRPCError { 48 + constructor(src: XRPCError) { 49 + super(src.status, src.error, src.message, src.headers, { cause: src }) 50 + } 51 + } 52 + 53 + export function toKnownErr(e: any) { 54 + if (e instanceof XRPCError) { 55 + if (e.error === 'InvalidSwap') return new InvalidSwapError(e) 56 + } 57 + 58 + return e 59 + }
+45
lexicons/src/types/com/atproto/repo/describeRepo.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'com.atproto.repo.describeRepo' 13 + 14 + export interface QueryParams { 15 + /** The handle or DID of the repo. */ 16 + repo: string 17 + } 18 + 19 + export type InputSchema = undefined 20 + 21 + export interface OutputSchema { 22 + handle: string 23 + did: string 24 + /** The complete DID document for this account. */ 25 + didDoc: { [_ in string]: unknown } 26 + /** List of all the collections (NSIDs) for which this repo contains at least one record. */ 27 + collections: string[] 28 + /** Indicates if handle is currently valid (resolves bi-directionally) */ 29 + handleIsCorrect: boolean 30 + } 31 + 32 + export interface CallOptions { 33 + signal?: AbortSignal 34 + headers?: HeadersMap 35 + } 36 + 37 + export interface Response { 38 + success: boolean 39 + headers: HeadersMap 40 + data: OutputSchema 41 + } 42 + 43 + export function toKnownErr(e: any) { 44 + return e 45 + }
+56
lexicons/src/types/com/atproto/repo/getRecord.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'com.atproto.repo.getRecord' 13 + 14 + export interface QueryParams { 15 + /** The handle or DID of the repo. */ 16 + repo: string 17 + /** The NSID of the record collection. */ 18 + collection: string 19 + /** The Record Key. */ 20 + rkey: string 21 + /** The CID of the version of the record. If not specified, then return the most recent version. */ 22 + cid?: string 23 + } 24 + 25 + export type InputSchema = undefined 26 + 27 + export interface OutputSchema { 28 + uri: string 29 + cid?: string 30 + value: { [_ in string]: unknown } 31 + } 32 + 33 + export interface CallOptions { 34 + signal?: AbortSignal 35 + headers?: HeadersMap 36 + } 37 + 38 + export interface Response { 39 + success: boolean 40 + headers: HeadersMap 41 + data: OutputSchema 42 + } 43 + 44 + export class RecordNotFoundError extends XRPCError { 45 + constructor(src: XRPCError) { 46 + super(src.status, src.error, src.message, src.headers, { cause: src }) 47 + } 48 + } 49 + 50 + export function toKnownErr(e: any) { 51 + if (e instanceof XRPCError) { 52 + if (e.error === 'RecordNotFound') return new RecordNotFoundError(e) 53 + } 54 + 55 + return e 56 + }
+32
lexicons/src/types/com/atproto/repo/importRepo.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'com.atproto.repo.importRepo' 13 + 14 + export interface QueryParams {} 15 + 16 + export type InputSchema = string | Uint8Array | Blob 17 + 18 + export interface CallOptions { 19 + signal?: AbortSignal 20 + headers?: HeadersMap 21 + qp?: QueryParams 22 + encoding?: 'application/vnd.ipld.car' 23 + } 24 + 25 + export interface Response { 26 + success: boolean 27 + headers: HeadersMap 28 + } 29 + 30 + export function toKnownErr(e: any) { 31 + return e 32 + }
+55
lexicons/src/types/com/atproto/repo/listMissingBlobs.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'com.atproto.repo.listMissingBlobs' 13 + 14 + export interface QueryParams { 15 + limit?: number 16 + cursor?: string 17 + } 18 + 19 + export type InputSchema = undefined 20 + 21 + export interface OutputSchema { 22 + cursor?: string 23 + blobs: RecordBlob[] 24 + } 25 + 26 + export interface CallOptions { 27 + signal?: AbortSignal 28 + headers?: HeadersMap 29 + } 30 + 31 + export interface Response { 32 + success: boolean 33 + headers: HeadersMap 34 + data: OutputSchema 35 + } 36 + 37 + export function toKnownErr(e: any) { 38 + return e 39 + } 40 + 41 + export interface RecordBlob { 42 + $type?: 'com.atproto.repo.listMissingBlobs#recordBlob' 43 + cid: string 44 + recordUri: string 45 + } 46 + 47 + const hashRecordBlob = 'recordBlob' 48 + 49 + export function isRecordBlob<V>(v: V) { 50 + return is$typed(v, id, hashRecordBlob) 51 + } 52 + 53 + export function validateRecordBlob<V>(v: V) { 54 + return validate<RecordBlob & V>(v, id, hashRecordBlob) 55 + }
+67
lexicons/src/types/com/atproto/repo/listRecords.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'com.atproto.repo.listRecords' 13 + 14 + export interface QueryParams { 15 + /** The handle or DID of the repo. */ 16 + repo: string 17 + /** The NSID of the record type. */ 18 + collection: string 19 + /** The number of records to return. */ 20 + limit?: number 21 + cursor?: string 22 + /** DEPRECATED: The lowest sort-ordered rkey to start from (exclusive) */ 23 + rkeyStart?: string 24 + /** DEPRECATED: The highest sort-ordered rkey to stop at (exclusive) */ 25 + rkeyEnd?: string 26 + /** Flag to reverse the order of the returned records. */ 27 + reverse?: boolean 28 + } 29 + 30 + export type InputSchema = undefined 31 + 32 + export interface OutputSchema { 33 + cursor?: string 34 + records: Record[] 35 + } 36 + 37 + export interface CallOptions { 38 + signal?: AbortSignal 39 + headers?: HeadersMap 40 + } 41 + 42 + export interface Response { 43 + success: boolean 44 + headers: HeadersMap 45 + data: OutputSchema 46 + } 47 + 48 + export function toKnownErr(e: any) { 49 + return e 50 + } 51 + 52 + export interface Record { 53 + $type?: 'com.atproto.repo.listRecords#record' 54 + uri: string 55 + cid: string 56 + value: { [_ in string]: unknown } 57 + } 58 + 59 + const hashRecord = 'record' 60 + 61 + export function isRecord<V>(v: V) { 62 + return is$typed(v, id, hashRecord) 63 + } 64 + 65 + export function validateRecord<V>(v: V) { 66 + return validate<Record & V>(v, id, hashRecord) 67 + }
+66
lexicons/src/types/com/atproto/repo/putRecord.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + import type * as ComAtprotoRepoDefs from './defs.js' 10 + 11 + const is$typed = _is$typed, 12 + validate = _validate 13 + const id = 'com.atproto.repo.putRecord' 14 + 15 + export interface QueryParams {} 16 + 17 + export interface InputSchema { 18 + /** The handle or DID of the repo (aka, current account). */ 19 + repo: string 20 + /** The NSID of the record collection. */ 21 + collection: string 22 + /** The Record Key. */ 23 + rkey: string 24 + /** Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons. */ 25 + validate?: boolean 26 + /** The record to write. */ 27 + record: { [_ in string]: unknown } 28 + /** Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation */ 29 + swapRecord?: string | null 30 + /** Compare and swap with the previous commit by CID. */ 31 + swapCommit?: string 32 + } 33 + 34 + export interface OutputSchema { 35 + uri: string 36 + cid: string 37 + commit?: ComAtprotoRepoDefs.CommitMeta 38 + validationStatus?: 'valid' | 'unknown' | (string & {}) 39 + } 40 + 41 + export interface CallOptions { 42 + signal?: AbortSignal 43 + headers?: HeadersMap 44 + qp?: QueryParams 45 + encoding?: 'application/json' 46 + } 47 + 48 + export interface Response { 49 + success: boolean 50 + headers: HeadersMap 51 + data: OutputSchema 52 + } 53 + 54 + export class InvalidSwapError extends XRPCError { 55 + constructor(src: XRPCError) { 56 + super(src.status, src.error, src.message, src.headers, { cause: src }) 57 + } 58 + } 59 + 60 + export function toKnownErr(e: any) { 61 + if (e instanceof XRPCError) { 62 + if (e.error === 'InvalidSwap') return new InvalidSwapError(e) 63 + } 64 + 65 + return e 66 + }
+27
lexicons/src/types/com/atproto/repo/strongRef.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'com.atproto.repo.strongRef' 12 + 13 + export interface Main { 14 + $type?: 'com.atproto.repo.strongRef' 15 + uri: string 16 + cid: string 17 + } 18 + 19 + const hashMain = 'main' 20 + 21 + export function isMain<V>(v: V) { 22 + return is$typed(v, id, hashMain) 23 + } 24 + 25 + export function validateMain<V>(v: V) { 26 + return validate<Main & V>(v, id, hashMain) 27 + }
+37
lexicons/src/types/com/atproto/repo/uploadBlob.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 6 + import { CID } from 'multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons' 8 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'com.atproto.repo.uploadBlob' 13 + 14 + export interface QueryParams {} 15 + 16 + export type InputSchema = string | Uint8Array | Blob 17 + 18 + export interface OutputSchema { 19 + blob: BlobRef 20 + } 21 + 22 + export interface CallOptions { 23 + signal?: AbortSignal 24 + headers?: HeadersMap 25 + qp?: QueryParams 26 + encoding?: string 27 + } 28 + 29 + export interface Response { 30 + success: boolean 31 + headers: HeadersMap 32 + data: OutputSchema 33 + } 34 + 35 + export function toKnownErr(e: any) { 36 + return e 37 + }
+27
lexicons/src/types/pub/leaflet/blocks/header.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'pub.leaflet.blocks.header' 12 + 13 + export interface Main { 14 + $type?: 'pub.leaflet.blocks.header' 15 + level?: number 16 + plaintext?: string 17 + } 18 + 19 + const hashMain = 'main' 20 + 21 + export function isMain<V>(v: V) { 22 + return is$typed(v, id, hashMain) 23 + } 24 + 25 + export function validateMain<V>(v: V) { 26 + return validate<Main & V>(v, id, hashMain) 27 + }
+45
lexicons/src/types/pub/leaflet/blocks/image.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'pub.leaflet.blocks.image' 12 + 13 + export interface Main { 14 + $type?: 'pub.leaflet.blocks.image' 15 + image: BlobRef 16 + /** Alt text description of the image, for accessibility. */ 17 + alt?: string 18 + aspectRatio?: AspectRatio 19 + } 20 + 21 + const hashMain = 'main' 22 + 23 + export function isMain<V>(v: V) { 24 + return is$typed(v, id, hashMain) 25 + } 26 + 27 + export function validateMain<V>(v: V) { 28 + return validate<Main & V>(v, id, hashMain) 29 + } 30 + 31 + export interface AspectRatio { 32 + $type?: 'pub.leaflet.blocks.image#aspectRatio' 33 + width: number 34 + height: number 35 + } 36 + 37 + const hashAspectRatio = 'aspectRatio' 38 + 39 + export function isAspectRatio<V>(v: V) { 40 + return is$typed(v, id, hashAspectRatio) 41 + } 42 + 43 + export function validateAspectRatio<V>(v: V) { 44 + return validate<AspectRatio & V>(v, id, hashAspectRatio) 45 + }
+26
lexicons/src/types/pub/leaflet/blocks/text.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'pub.leaflet.blocks.text' 12 + 13 + export interface Main { 14 + $type?: 'pub.leaflet.blocks.text' 15 + plaintext?: string 16 + } 17 + 18 + const hashMain = 'main' 19 + 20 + export function isMain<V>(v: V) { 21 + return is$typed(v, id, hashMain) 22 + } 23 + 24 + export function validateMain<V>(v: V) { 25 + return validate<Main & V>(v, id, hashMain) 26 + }
+32
lexicons/src/types/pub/leaflet/document.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../util' 8 + import type * as PubLeafletPagesLinearDocument from './pages/linearDocument.js' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'pub.leaflet.document' 13 + 14 + export interface Record { 15 + $type: 'pub.leaflet.document' 16 + title: string 17 + publishedAt?: string 18 + publication: string 19 + author: string 20 + pages: ($Typed<PubLeafletPagesLinearDocument.Main> | { $type: string })[] 21 + [k: string]: unknown 22 + } 23 + 24 + const hashRecord = 'main' 25 + 26 + export function isRecord<V>(v: V) { 27 + return is$typed(v, id, hashRecord) 28 + } 29 + 30 + export function validateRecord<V>(v: V) { 31 + return validate<Record & V>(v, id, hashRecord, true) 32 + }
+57
lexicons/src/types/pub/leaflet/pages/linearDocument.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + import type * as PubLeafletBlocksText from '../blocks/text.js' 9 + import type * as PubLeafletBlocksHeader from '../blocks/header.js' 10 + import type * as PubLeafletBlocksImage from '../blocks/image.js' 11 + 12 + const is$typed = _is$typed, 13 + validate = _validate 14 + const id = 'pub.leaflet.pages.linearDocument' 15 + 16 + export interface Main { 17 + $type?: 'pub.leaflet.pages.linearDocument' 18 + blocks?: Block[] 19 + } 20 + 21 + const hashMain = 'main' 22 + 23 + export function isMain<V>(v: V) { 24 + return is$typed(v, id, hashMain) 25 + } 26 + 27 + export function validateMain<V>(v: V) { 28 + return validate<Main & V>(v, id, hashMain) 29 + } 30 + 31 + export interface Block { 32 + $type?: 'pub.leaflet.pages.linearDocument#block' 33 + block: 34 + | $Typed<PubLeafletBlocksText.Main> 35 + | $Typed<PubLeafletBlocksHeader.Main> 36 + | $Typed<PubLeafletBlocksImage.Main> 37 + | { $type: string } 38 + alignment?: 39 + | 'lex:pub.leaflet.pages.linearDocument#textAlignLeft' 40 + | 'lex:pub.leaflet.pages.linearDocument#textAlignCenter' 41 + | 'lex:pub.leaflet.pages.linearDocument#textAlignRight' 42 + | (string & {}) 43 + } 44 + 45 + const hashBlock = 'block' 46 + 47 + export function isBlock<V>(v: V) { 48 + return is$typed(v, id, hashBlock) 49 + } 50 + 51 + export function validateBlock<V>(v: V) { 52 + return validate<Block & V>(v, id, hashBlock) 53 + } 54 + 55 + export const TEXTALIGNLEFT = `${id}#textAlignLeft` 56 + export const TEXTALIGNCENTER = `${id}#textAlignCenter` 57 + export const TEXTALIGNRIGHT = `${id}#textAlignRight`
+30
lexicons/src/types/pub/leaflet/post.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../util' 8 + import type * as ComAtprotoRepoStrongRef from '../../com/atproto/repo/strongRef.js' 9 + 10 + const is$typed = _is$typed, 11 + validate = _validate 12 + const id = 'pub.leaflet.post' 13 + 14 + export interface Record { 15 + $type: 'pub.leaflet.post' 16 + publication?: string 17 + post: ComAtprotoRepoStrongRef.Main 18 + publishedAt: string 19 + [k: string]: unknown 20 + } 21 + 22 + const hashRecord = 'main' 23 + 24 + export function isRecord<V>(v: V) { 25 + return is$typed(v, id, hashRecord) 26 + } 27 + 28 + export function validateRecord<V>(v: V) { 29 + return validate<Record & V>(v, id, hashRecord, true) 30 + }
+28
lexicons/src/types/pub/leaflet/publication.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'pub.leaflet.publication' 12 + 13 + export interface Record { 14 + $type: 'pub.leaflet.publication' 15 + name: string 16 + description?: string 17 + [k: string]: unknown 18 + } 19 + 20 + const hashRecord = 'main' 21 + 22 + export function isRecord<V>(v: V) { 23 + return is$typed(v, id, hashRecord) 24 + } 25 + 26 + export function validateRecord<V>(v: V) { 27 + return validate<Record & V>(v, id, hashRecord, true) 28 + }
+82
lexicons/src/util.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + 5 + import { ValidationResult } from '@atproto/lexicon' 6 + 7 + export type OmitKey<T, K extends keyof T> = { 8 + [K2 in keyof T as K2 extends K ? never : K2]: T[K2] 9 + } 10 + 11 + export type $Typed<V, T extends string = string> = V & { $type: T } 12 + export type Un$Typed<V extends { $type?: string }> = OmitKey<V, '$type'> 13 + 14 + export type $Type<Id extends string, Hash extends string> = Hash extends 'main' 15 + ? Id 16 + : `${Id}#${Hash}` 17 + 18 + function isObject<V>(v: V): v is V & object { 19 + return v != null && typeof v === 'object' 20 + } 21 + 22 + function is$type<Id extends string, Hash extends string>( 23 + $type: unknown, 24 + id: Id, 25 + hash: Hash, 26 + ): $type is $Type<Id, Hash> { 27 + return hash === 'main' 28 + ? $type === id 29 + : // $type === `${id}#${hash}` 30 + typeof $type === 'string' && 31 + $type.length === id.length + 1 + hash.length && 32 + $type.charCodeAt(id.length) === 35 /* '#' */ && 33 + $type.startsWith(id) && 34 + $type.endsWith(hash) 35 + } 36 + 37 + export type $TypedObject< 38 + V, 39 + Id extends string, 40 + Hash extends string, 41 + > = V extends { 42 + $type: $Type<Id, Hash> 43 + } 44 + ? V 45 + : V extends { $type?: string } 46 + ? V extends { $type?: infer T extends $Type<Id, Hash> } 47 + ? V & { $type: T } 48 + : never 49 + : V & { $type: $Type<Id, Hash> } 50 + 51 + export function is$typed<V, Id extends string, Hash extends string>( 52 + v: V, 53 + id: Id, 54 + hash: Hash, 55 + ): v is $TypedObject<V, Id, Hash> { 56 + return isObject(v) && '$type' in v && is$type(v.$type, id, hash) 57 + } 58 + 59 + export function maybe$typed<V, Id extends string, Hash extends string>( 60 + v: V, 61 + id: Id, 62 + hash: Hash, 63 + ): v is V & object & { $type?: $Type<Id, Hash> } { 64 + return ( 65 + isObject(v) && 66 + ('$type' in v ? v.$type === undefined || is$type(v.$type, id, hash) : true) 67 + ) 68 + } 69 + 70 + export type Validator<R = unknown> = (v: unknown) => ValidationResult<R> 71 + export type ValidatorParam<V extends Validator> = 72 + V extends Validator<infer R> ? R : never 73 + 74 + /** 75 + * Utility function that allows to convert a "validate*" utility function into a 76 + * type predicate. 77 + */ 78 + export function asPredicate<V extends Validator>(validate: V) { 79 + return function <T>(v: T): v is T & ValidatorParam<V> { 80 + return validate(v).success 81 + } 82 + }
+104
lexicons/utils.ts
··· 1 + import { 2 + LexArray, 3 + // lexPrimitive 4 + LexBoolean, 5 + LexInteger, 6 + LexString, 7 + LexUnknown, 8 + // lexIpldType 9 + LexBytes, 10 + LexCidLink, 11 + // lexRefVariant 12 + LexRef, 13 + LexRefUnion, 14 + // other 15 + LexBlob, 16 + lexRecord, 17 + LexRecord, 18 + LexObject, 19 + LexiconDoc, 20 + LexToken, 21 + } from "@atproto/lexicon"; 22 + 23 + export const refValue = <T extends Pick<LexiconDoc, "defs" | "id">>( 24 + l: T | null, 25 + k?: keyof T["defs"] & string, 26 + ) => { 27 + //Could improve this somehow, to ensure you have to pass in K if l is null? 28 + if (l === null) return `#${k}` || ""; 29 + return k ? `${l.id}#k` : l.id; 30 + }; 31 + 32 + export const lexicon = <T extends { defs: LexiconDoc["defs"] }>(args: T) => { 33 + return { 34 + lexicon: 1, 35 + ...args, 36 + }; 37 + }; 38 + 39 + export const record = ( 40 + args: Omit<LexRecord, "type" | "key"> & { 41 + key: "tid" | "nsid" | `literal:${string}` | "any"; 42 + }, 43 + ): LexRecord => ({ 44 + type: "record", 45 + ...args, 46 + }); 47 + 48 + export const string = (args?: Omit<LexString, "type">) => 49 + ({ type: "string", ...args }) as const; 50 + export const token = (l?: { description: string }): LexToken => ({ 51 + type: "token", 52 + description: l?.description, 53 + }); 54 + 55 + export const integer = (args?: Omit<LexInteger, "type">) => 56 + ({ 57 + type: "integer", 58 + ...args, 59 + }) as const; 60 + 61 + export const ref = (ref: string): LexRef => ({ type: "ref", ref }); 62 + 63 + export const array = (args: Omit<LexArray, "type">): LexArray => ({ 64 + type: "array", 65 + ...args, 66 + }); 67 + 68 + export const object = < 69 + Properties extends { 70 + [k: string]: 71 + | LexArray 72 + // lexPrimitive 73 + | LexBoolean 74 + | LexInteger 75 + | LexString 76 + | LexUnknown 77 + // lexIpldType 78 + | LexBytes 79 + | LexCidLink 80 + // lexRefVariant 81 + | LexRef 82 + | LexRefUnion 83 + // other 84 + | LexBlob; 85 + }, 86 + Required extends (keyof Properties & string)[], 87 + >( 88 + args: Omit<LexObject, "type" | "properties" | "required"> & { 89 + properties: Properties; 90 + required?: Required; 91 + }, 92 + ): LexObject => ({ 93 + type: "object", 94 + ...args, 95 + }); 96 + 97 + export const blob = (args: Omit<LexBlob, "type">): LexBlob => ({ 98 + type: "blob", 99 + ...args, 100 + }); 101 + export const union = (args: Omit<LexRefUnion, "type">): LexRefUnion => ({ 102 + type: "union", 103 + ...args, 104 + });
+7
next.config.js
··· 2 2 3 3 /** @type {import('next').NextConfig} */ 4 4 const nextConfig = { 5 + webpack: (config) => { 6 + config.resolve.extensionAlias = { 7 + ".js": [".ts", ".tsx", ".js"], 8 + }; 9 + 10 + return config; 11 + }, 5 12 async rewrites() { 6 13 return [ 7 14 {
+2114 -47
package-lock.json
··· 10 10 "license": "ISC", 11 11 "dependencies": { 12 12 "@atproto/api": "^0.14.2", 13 + "@atproto/common": "^0.4.8", 14 + "@atproto/identity": "^0.4.6", 15 + "@atproto/oauth-client-node": "^0.2.8", 16 + "@atproto/sync": "^0.1.17", 17 + "@atproto/syntax": "^0.3.3", 18 + "@atproto/xrpc": "^0.6.9", 13 19 "@mdx-js/loader": "^3.1.0", 14 20 "@mdx-js/react": "^3.1.0", 15 21 "@next/mdx": "^15.0.3", ··· 33 39 "drizzle-orm": "^0.30.10", 34 40 "fractional-indexing": "^3.2.0", 35 41 "linkifyjs": "^4.2.0", 42 + "multiformats": "^13.3.2", 36 43 "next": "^14.2.4", 37 44 "postgres": "^3.4.4", 38 45 "prosemirror-commands": "^1.5.2", ··· 66 73 "zustand": "^4.5.2" 67 74 }, 68 75 "devDependencies": { 76 + "@atproto/lex-cli": "^0.6.1", 77 + "@atproto/lexicon": "^0.4.7", 69 78 "@cloudflare/workers-types": "^4.20240512.0", 70 79 "@types/react": "18.3.2", 71 80 "@types/react-dom": "^18.3.0", ··· 78 87 "prettier": "3.2.5", 79 88 "supabase": "^1.187.3", 80 89 "tailwindcss": "^3.4.3", 90 + "tsx": "^4.19.3", 81 91 "typescript": "^5.5.3", 82 92 "wrangler": "^3.56.0" 83 93 } ··· 94 104 "url": "https://github.com/sponsors/sindresorhus" 95 105 } 96 106 }, 107 + "node_modules/@atproto-labs/did-resolver": { 108 + "version": "0.1.8", 109 + "resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.1.8.tgz", 110 + "integrity": "sha512-wcbBTu0YsAUCzvKHTuk90ax4+gwj8wlPFY+rR96O7/rtSVjx4xz06Fdri0amAzSoupUeZ7swcZVKDqHD8KB8HA==", 111 + "license": "MIT", 112 + "dependencies": { 113 + "@atproto-labs/fetch": "0.2.0", 114 + "@atproto-labs/pipe": "0.1.0", 115 + "@atproto-labs/simple-store": "0.1.1", 116 + "@atproto-labs/simple-store-memory": "0.1.1", 117 + "@atproto/did": "0.1.3", 118 + "zod": "^3.23.8" 119 + } 120 + }, 121 + "node_modules/@atproto-labs/fetch": { 122 + "version": "0.2.0", 123 + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.2.0.tgz", 124 + "integrity": "sha512-RD8grUzZdQaC+1GwObz6rZ7MKraS77Z72uZNvcqUzQEBc2oF7fTW6BtkI0csJMFkW+qWKlR3YQlZxsZQ4x6H3g==", 125 + "license": "MIT", 126 + "dependencies": { 127 + "@atproto-labs/pipe": "0.1.0" 128 + }, 129 + "optionalDependencies": { 130 + "zod": "^3.23.8" 131 + } 132 + }, 133 + "node_modules/@atproto-labs/fetch-node": { 134 + "version": "0.1.6", 135 + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch-node/-/fetch-node-0.1.6.tgz", 136 + "integrity": "sha512-MtisrDQZuBiR3yUyhVqaNrukGTZfZHANG23E1w5t4biz1ONWWSFc1CkqUGOHPJJ7JpjaNbHRf1kfKsMZotQZsQ==", 137 + "license": "MIT", 138 + "dependencies": { 139 + "@atproto-labs/fetch": "0.2.0", 140 + "@atproto-labs/pipe": "0.1.0", 141 + "ipaddr.js": "^2.1.0", 142 + "psl": "^1.9.0", 143 + "undici": "^6.14.1" 144 + } 145 + }, 146 + "node_modules/@atproto-labs/handle-resolver": { 147 + "version": "0.1.5", 148 + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.1.5.tgz", 149 + "integrity": "sha512-3Uv5DUswmiUWn0oO3XML7T6RiM8aq+A4lACBRRasegsr6fytxATJE38UiwDmDRWdXxhftnPlmTWfJ2oZ/pqDWQ==", 150 + "license": "MIT", 151 + "dependencies": { 152 + "@atproto-labs/simple-store": "0.1.1", 153 + "@atproto-labs/simple-store-memory": "0.1.1", 154 + "@atproto/did": "0.1.3", 155 + "zod": "^3.23.8" 156 + } 157 + }, 158 + "node_modules/@atproto-labs/handle-resolver-node": { 159 + "version": "0.1.11", 160 + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver-node/-/handle-resolver-node-0.1.11.tgz", 161 + "integrity": "sha512-Lfm3LgKr1dkHgnd8UX6JvyywflUJpRXQtZwgDXNnj+3nAb8amfDy+mfx0Cu8ym2T2uzEuGRnfmXzLEp7EKbADw==", 162 + "license": "MIT", 163 + "dependencies": { 164 + "@atproto-labs/fetch-node": "0.1.6", 165 + "@atproto-labs/handle-resolver": "0.1.5", 166 + "@atproto/did": "0.1.3" 167 + } 168 + }, 169 + "node_modules/@atproto-labs/identity-resolver": { 170 + "version": "0.1.10", 171 + "resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.1.10.tgz", 172 + "integrity": "sha512-V8cwLikQJrrIubZcbS3phiw3FZ4JleZ43EOyGq2pVBRsQgynSIB/tzTTw8UNuKPeqR/iK1CBjevnQJ4ENOr5AQ==", 173 + "license": "MIT", 174 + "dependencies": { 175 + "@atproto-labs/did-resolver": "0.1.8", 176 + "@atproto-labs/handle-resolver": "0.1.5", 177 + "@atproto/syntax": "0.3.1" 178 + } 179 + }, 180 + "node_modules/@atproto-labs/identity-resolver/node_modules/@atproto/syntax": { 181 + "version": "0.3.1", 182 + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.1.tgz", 183 + "integrity": "sha512-fzW0Mg1QUOVCWUD3RgEsDt6d1OZ6DdFmbKcDdbzUfh0t4rhtRAC05KbZYmxuMPWDAiJ4BbbQ5dkAc/mNypMXkw==", 184 + "license": "MIT" 185 + }, 186 + "node_modules/@atproto-labs/pipe": { 187 + "version": "0.1.0", 188 + "resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.0.tgz", 189 + "integrity": "sha512-ghOqHFyJlQVFPESzlVHjKroP0tPzbmG5Jms0dNI9yLDEfL8xp4OFPWLX4f6T8mRq69wWs4nIDM3sSsFbFqLa1w==", 190 + "license": "MIT" 191 + }, 192 + "node_modules/@atproto-labs/simple-store": { 193 + "version": "0.1.1", 194 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.1.1.tgz", 195 + "integrity": "sha512-WKILW2b3QbAYKh+w5U2x6p5FqqLl0nAeLwGeDY+KjX01K4Dq3vQTR9b/qNp0jZm48CabPQVrqCv0PPU9LgRRRg==", 196 + "license": "MIT" 197 + }, 198 + "node_modules/@atproto-labs/simple-store-memory": { 199 + "version": "0.1.1", 200 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.1.tgz", 201 + "integrity": "sha512-PCRqhnZ8NBNBvLku53O56T0lsVOtclfIrQU/rwLCc4+p45/SBPrRYNBi6YFq5rxZbK6Njos9MCmILV/KLQxrWA==", 202 + "license": "MIT", 203 + "dependencies": { 204 + "@atproto-labs/simple-store": "0.1.1", 205 + "lru-cache": "^10.2.0" 206 + } 207 + }, 97 208 "node_modules/@atproto/api": { 98 - "version": "0.14.2", 99 - "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.14.2.tgz", 100 - "integrity": "sha512-TRhgRWOftDOTNWcqP0kE1upDn0++o37imW91NaBVkeapqK7QToVsiJbCQC5l1+EPJ7/BJ5o4IgjZx5ZdENh07A==", 209 + "version": "0.14.9", 210 + "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.14.9.tgz", 211 + "integrity": "sha512-9S7Vl6gK8hmy0+Gw5AWriUsQfQYZxwW7yTK5UdPPGlmjvQP49YeSLrsxB1ZkTyrlLSG2tpYrGsN4vco6KOORAQ==", 101 212 "license": "MIT", 102 213 "dependencies": { 103 214 "@atproto/common-web": "^0.4.0", 104 - "@atproto/lexicon": "^0.4.7", 105 - "@atproto/syntax": "^0.3.3", 106 - "@atproto/xrpc": "^0.6.9", 215 + "@atproto/lexicon": "^0.4.8", 216 + "@atproto/syntax": "^0.3.4", 217 + "@atproto/xrpc": "^0.6.10", 107 218 "await-lock": "^2.2.2", 108 219 "multiformats": "^9.9.0", 109 220 "tlds": "^1.234.0", 110 221 "zod": "^3.23.8" 111 222 } 112 223 }, 224 + "node_modules/@atproto/api/node_modules/multiformats": { 225 + "version": "9.9.0", 226 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 227 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 228 + "license": "(Apache-2.0 AND MIT)" 229 + }, 230 + "node_modules/@atproto/common": { 231 + "version": "0.4.8", 232 + "resolved": "https://registry.npmjs.org/@atproto/common/-/common-0.4.8.tgz", 233 + "integrity": "sha512-/etCtnWQGLcfiGhIPwxAWrzgzoGB22nMWMeQcU6xZgRT4Cqrfg3A08jAMIHqve/AQpL+6D82lHYp36CG7a5G0w==", 234 + "license": "MIT", 235 + "dependencies": { 236 + "@atproto/common-web": "^0.4.0", 237 + "@ipld/dag-cbor": "^7.0.3", 238 + "cbor-x": "^1.5.1", 239 + "iso-datestring-validator": "^2.2.2", 240 + "multiformats": "^9.9.0", 241 + "pino": "^8.21.0" 242 + }, 243 + "engines": { 244 + "node": ">=18.7.0" 245 + } 246 + }, 113 247 "node_modules/@atproto/common-web": { 114 248 "version": "0.4.0", 115 249 "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.0.tgz", ··· 122 256 "zod": "^3.23.8" 123 257 } 124 258 }, 259 + "node_modules/@atproto/common-web/node_modules/multiformats": { 260 + "version": "9.9.0", 261 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 262 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 263 + "license": "(Apache-2.0 AND MIT)" 264 + }, 265 + "node_modules/@atproto/common/node_modules/multiformats": { 266 + "version": "9.9.0", 267 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 268 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 269 + "license": "(Apache-2.0 AND MIT)" 270 + }, 271 + "node_modules/@atproto/crypto": { 272 + "version": "0.4.4", 273 + "resolved": "https://registry.npmjs.org/@atproto/crypto/-/crypto-0.4.4.tgz", 274 + "integrity": "sha512-Yq9+crJ7WQl7sxStVpHgie5Z51R05etaK9DLWYG/7bR5T4bhdcIgF6IfklLShtZwLYdVVj+K15s0BqW9a8PSDA==", 275 + "license": "MIT", 276 + "dependencies": { 277 + "@noble/curves": "^1.7.0", 278 + "@noble/hashes": "^1.6.1", 279 + "uint8arrays": "3.0.0" 280 + }, 281 + "engines": { 282 + "node": ">=18.7.0" 283 + } 284 + }, 285 + "node_modules/@atproto/did": { 286 + "version": "0.1.3", 287 + "resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.1.3.tgz", 288 + "integrity": "sha512-ULD8Gw/KRRwLFZ2Z2L4DjmdOMrg8IYYlcjdSc+GQ2/QJSVnD2zaJJVTLd3vls121wGt/583rNaiZTT2DpBze4w==", 289 + "license": "MIT", 290 + "dependencies": { 291 + "zod": "^3.23.8" 292 + } 293 + }, 294 + "node_modules/@atproto/identity": { 295 + "version": "0.4.6", 296 + "resolved": "https://registry.npmjs.org/@atproto/identity/-/identity-0.4.6.tgz", 297 + "integrity": "sha512-fJq/cIp9MOgHxZfxuyki6mobk0QxRnbts53DstRixlvb5mOoxwttb9Gp6A8u9q49zBsfOmXNTHmP97I9iMHmTQ==", 298 + "license": "MIT", 299 + "dependencies": { 300 + "@atproto/common-web": "^0.4.0", 301 + "@atproto/crypto": "^0.4.4" 302 + }, 303 + "engines": { 304 + "node": ">=18.7.0" 305 + } 306 + }, 307 + "node_modules/@atproto/jwk": { 308 + "version": "0.1.2", 309 + "resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.1.2.tgz", 310 + "integrity": "sha512-VTQOPaXevW42PQNUD6xJSa6BSjJKKz2DmJqaBP1TkCnLQSr1iU04yyvBSPijQpvWaZWnPnn06NQiorsv7INX6Q==", 311 + "license": "MIT", 312 + "dependencies": { 313 + "multiformats": "^9.9.0", 314 + "zod": "^3.23.8" 315 + } 316 + }, 317 + "node_modules/@atproto/jwk-jose": { 318 + "version": "0.1.3", 319 + "resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.3.tgz", 320 + "integrity": "sha512-kPlX9n+WrSx1nzPODxeXncDZ5MqWOaneo+8zNCufIgHdzkDgrGmw8GraUmXZMxmsUthnx52B7vVMUapM2hHetw==", 321 + "license": "MIT", 322 + "dependencies": { 323 + "@atproto/jwk": "0.1.2", 324 + "jose": "^5.2.0" 325 + } 326 + }, 327 + "node_modules/@atproto/jwk-webcrypto": { 328 + "version": "0.1.3", 329 + "resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.1.3.tgz", 330 + "integrity": "sha512-32gngFZSa0lK/31ttlY+BNrNh6BkCLA3voa7KHdN0r1YMfqFzTPX+RMAOQeBTK7FY9Z0SC65l0+6tSId24TgoQ==", 331 + "license": "MIT", 332 + "dependencies": { 333 + "@atproto/jwk": "0.1.2", 334 + "@atproto/jwk-jose": "0.1.3", 335 + "zod": "^3.23.8" 336 + } 337 + }, 338 + "node_modules/@atproto/jwk/node_modules/multiformats": { 339 + "version": "9.9.0", 340 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 341 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 342 + "license": "(Apache-2.0 AND MIT)" 343 + }, 344 + "node_modules/@atproto/lex-cli": { 345 + "version": "0.6.2", 346 + "resolved": "https://registry.npmjs.org/@atproto/lex-cli/-/lex-cli-0.6.2.tgz", 347 + "integrity": "sha512-YbypfXBOYdZQATgQRRMpTwcG42/JmRs3iYnN6hQH4ljjn+t5nbDtdZjUF5okiWI7LK+yvOrgagxosIAjjjSe8Q==", 348 + "dev": true, 349 + "license": "MIT", 350 + "dependencies": { 351 + "@atproto/lexicon": "^0.4.8", 352 + "@atproto/syntax": "^0.3.4", 353 + "chalk": "^4.1.2", 354 + "commander": "^9.4.0", 355 + "prettier": "^3.2.5", 356 + "ts-morph": "^16.0.0", 357 + "yesno": "^0.4.0", 358 + "zod": "^3.23.8" 359 + }, 360 + "bin": { 361 + "lex": "dist/index.js" 362 + }, 363 + "engines": { 364 + "node": ">=18.7.0" 365 + } 366 + }, 125 367 "node_modules/@atproto/lexicon": { 126 - "version": "0.4.7", 127 - "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.7.tgz", 128 - "integrity": "sha512-/x6h3tAiDNzSi4eXtC8ke65B7UzsagtlGRHmUD95698x5lBRpDnpizj0fZWTZVYed5qnOmz/ZEue+v3wDmO61g==", 368 + "version": "0.4.8", 369 + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.8.tgz", 370 + "integrity": "sha512-NPhu4MNHqft4muvHvcU0BrkWoEpTI+OmbQzvZzzRpw54MW3PfrQ4TPEpAfPOrWugPB9y4mD+l8OMN1c9eOGWMQ==", 129 371 "license": "MIT", 130 372 "dependencies": { 131 373 "@atproto/common-web": "^0.4.0", 132 - "@atproto/syntax": "^0.3.3", 374 + "@atproto/syntax": "^0.3.4", 133 375 "iso-datestring-validator": "^2.2.2", 134 376 "multiformats": "^9.9.0", 135 377 "zod": "^3.23.8" 136 378 } 137 379 }, 380 + "node_modules/@atproto/lexicon/node_modules/multiformats": { 381 + "version": "9.9.0", 382 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 383 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 384 + "license": "(Apache-2.0 AND MIT)" 385 + }, 386 + "node_modules/@atproto/oauth-client": { 387 + "version": "0.3.7", 388 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.3.7.tgz", 389 + "integrity": "sha512-CXikk9FwkL8sEATHZlAEM3qsIjIT8wkh9EShXceEgS3f4BSAbSpnGvYjiV2wdrykSVmbMWH1wynl6T/aeHQJEg==", 390 + "license": "MIT", 391 + "dependencies": { 392 + "@atproto-labs/did-resolver": "0.1.8", 393 + "@atproto-labs/fetch": "0.2.0", 394 + "@atproto-labs/handle-resolver": "0.1.5", 395 + "@atproto-labs/identity-resolver": "0.1.10", 396 + "@atproto-labs/simple-store": "0.1.1", 397 + "@atproto-labs/simple-store-memory": "0.1.1", 398 + "@atproto/did": "0.1.3", 399 + "@atproto/jwk": "0.1.2", 400 + "@atproto/oauth-types": "0.2.2", 401 + "@atproto/xrpc": "0.6.6", 402 + "multiformats": "^9.9.0", 403 + "zod": "^3.23.8" 404 + } 405 + }, 406 + "node_modules/@atproto/oauth-client-node": { 407 + "version": "0.2.8", 408 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client-node/-/oauth-client-node-0.2.8.tgz", 409 + "integrity": "sha512-EHxdfNpRvwnlxHFCYjl5+ckmPKwYe/jSMN2RksudrSg/XivRzJisgBMOsQ2FnuXIiC9eh4HZ+MrxnoEpT20tDA==", 410 + "license": "MIT", 411 + "dependencies": { 412 + "@atproto-labs/did-resolver": "0.1.8", 413 + "@atproto-labs/handle-resolver-node": "0.1.11", 414 + "@atproto-labs/simple-store": "0.1.1", 415 + "@atproto/did": "0.1.3", 416 + "@atproto/jwk": "0.1.2", 417 + "@atproto/jwk-jose": "0.1.3", 418 + "@atproto/jwk-webcrypto": "0.1.3", 419 + "@atproto/oauth-client": "0.3.7", 420 + "@atproto/oauth-types": "0.2.2" 421 + } 422 + }, 423 + "node_modules/@atproto/oauth-client/node_modules/@atproto/xrpc": { 424 + "version": "0.6.6", 425 + "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.6.6.tgz", 426 + "integrity": "sha512-umXEYVMo9/pyIBoKmIAIi64RXDW9tSXY+wqztlQ6I2GZtjLfNZqmAWU+wADk3SxUe54mvjxxGyA4TtyGtDMfhA==", 427 + "license": "MIT", 428 + "dependencies": { 429 + "@atproto/lexicon": "^0.4.5", 430 + "zod": "^3.23.8" 431 + } 432 + }, 433 + "node_modules/@atproto/oauth-client/node_modules/multiformats": { 434 + "version": "9.9.0", 435 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 436 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 437 + "license": "(Apache-2.0 AND MIT)" 438 + }, 439 + "node_modules/@atproto/oauth-types": { 440 + "version": "0.2.2", 441 + "resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.2.2.tgz", 442 + "integrity": "sha512-UMTfJwKD/mIZEXxVT02XWYMtRJAu4iytxhlScH48Q/40nOa6oV4wUFij0gnV4NAQkjHMaYh39ChRMjjKHeypJA==", 443 + "license": "MIT", 444 + "dependencies": { 445 + "@atproto/jwk": "0.1.2", 446 + "zod": "^3.23.8" 447 + } 448 + }, 449 + "node_modules/@atproto/repo": { 450 + "version": "0.7.1", 451 + "resolved": "https://registry.npmjs.org/@atproto/repo/-/repo-0.7.1.tgz", 452 + "integrity": "sha512-0U7iuO+Xf1H/2s0KHOoW/QCSRnegMOoCqHi8PJcB0sOx91h5mAB71nltxhOUhYfdVCLnXATSO/Xkux/6cjsQZw==", 453 + "license": "MIT", 454 + "dependencies": { 455 + "@atproto/common": "^0.4.8", 456 + "@atproto/common-web": "^0.4.0", 457 + "@atproto/crypto": "^0.4.4", 458 + "@atproto/lexicon": "^0.4.8", 459 + "@ipld/car": "^3.2.3", 460 + "@ipld/dag-cbor": "^7.0.0", 461 + "multiformats": "^9.9.0", 462 + "uint8arrays": "3.0.0", 463 + "zod": "^3.23.8" 464 + }, 465 + "engines": { 466 + "node": ">=18.7.0" 467 + } 468 + }, 469 + "node_modules/@atproto/repo/node_modules/multiformats": { 470 + "version": "9.9.0", 471 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 472 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 473 + "license": "(Apache-2.0 AND MIT)" 474 + }, 475 + "node_modules/@atproto/sync": { 476 + "version": "0.1.17", 477 + "resolved": "https://registry.npmjs.org/@atproto/sync/-/sync-0.1.17.tgz", 478 + "integrity": "sha512-3+wGTy1fsL06KraOYNCIPUUsKMIplPFDkXffx5ZrbpNxWKAJ5FNPLnROuVnRrG0w9yPrNSTEdd0lCsimZOufqg==", 479 + "license": "MIT", 480 + "dependencies": { 481 + "@atproto/common": "^0.4.8", 482 + "@atproto/identity": "^0.4.6", 483 + "@atproto/lexicon": "^0.4.8", 484 + "@atproto/repo": "^0.7.1", 485 + "@atproto/syntax": "^0.3.4", 486 + "@atproto/xrpc-server": "^0.7.12", 487 + "multiformats": "^9.9.0", 488 + "p-queue": "^6.6.2", 489 + "ws": "^8.12.0" 490 + }, 491 + "engines": { 492 + "node": ">=18.7.0" 493 + } 494 + }, 495 + "node_modules/@atproto/sync/node_modules/multiformats": { 496 + "version": "9.9.0", 497 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 498 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 499 + "license": "(Apache-2.0 AND MIT)" 500 + }, 138 501 "node_modules/@atproto/syntax": { 139 - "version": "0.3.3", 140 - "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.3.tgz", 141 - "integrity": "sha512-F1LZweesNYdBbZBXVa72N/cSvchG8Q1tG4/209ZXbIuM3FwQtkgn+zgmmV4P4ORmhOeXPBNXvMBpcqiwx/gEQQ==", 502 + "version": "0.3.4", 503 + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.4.tgz", 504 + "integrity": "sha512-8CNmi5DipOLaVeSMPggMe7FCksVag0aO6XZy9WflbduTKM4dFZVCs4686UeMLfGRXX+X966XgwECHoLYrovMMg==", 142 505 "license": "MIT" 143 506 }, 144 507 "node_modules/@atproto/xrpc": { 145 - "version": "0.6.9", 146 - "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.6.9.tgz", 147 - "integrity": "sha512-vQGA7++DYMNaHx3C7vEjT+2X6hYYLG7JNbBnDLWu0km1/1KYXgRkAz4h+FfYqg1mvzvIorHU7DAs5wevkJDDlw==", 508 + "version": "0.6.10", 509 + "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.6.10.tgz", 510 + "integrity": "sha512-ClMiO+oAl3KrFe7sdo8Wzw81yV7EpEradZLJnYilPq4s7uF0by1jHGI/LarHBKHnE5RpaFpBC/5XD/ZzgmvAeg==", 511 + "license": "MIT", 512 + "dependencies": { 513 + "@atproto/lexicon": "^0.4.8", 514 + "zod": "^3.23.8" 515 + } 516 + }, 517 + "node_modules/@atproto/xrpc-server": { 518 + "version": "0.7.12", 519 + "resolved": "https://registry.npmjs.org/@atproto/xrpc-server/-/xrpc-server-0.7.12.tgz", 520 + "integrity": "sha512-h9AsFzMePjsw8VVpkT/UOJNcno42gKiT5BZwHYGI/F05klbiRVczL1CUHinFFjTKONbL95iPgY9JTGrYb7Ye2w==", 148 521 "license": "MIT", 149 522 "dependencies": { 150 - "@atproto/lexicon": "^0.4.7", 523 + "@atproto/common": "^0.4.8", 524 + "@atproto/crypto": "^0.4.4", 525 + "@atproto/lexicon": "^0.4.8", 526 + "@atproto/xrpc": "^0.6.10", 527 + "cbor-x": "^1.5.1", 528 + "express": "^4.17.2", 529 + "http-errors": "^2.0.0", 530 + "mime-types": "^2.1.35", 531 + "rate-limiter-flexible": "^2.4.1", 532 + "uint8arrays": "3.0.0", 533 + "ws": "^8.12.0", 151 534 "zod": "^3.23.8" 535 + }, 536 + "engines": { 537 + "node": ">=18.7.0" 152 538 } 153 539 }, 154 540 "node_modules/@babel/runtime": { ··· 169 555 "engines": { 170 556 "node": ">= 16" 171 557 } 558 + }, 559 + "node_modules/@cbor-extract/cbor-extract-darwin-arm64": { 560 + "version": "2.2.0", 561 + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.2.0.tgz", 562 + "integrity": "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==", 563 + "cpu": [ 564 + "arm64" 565 + ], 566 + "license": "MIT", 567 + "optional": true, 568 + "os": [ 569 + "darwin" 570 + ] 571 + }, 572 + "node_modules/@cbor-extract/cbor-extract-darwin-x64": { 573 + "version": "2.2.0", 574 + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.2.0.tgz", 575 + "integrity": "sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==", 576 + "cpu": [ 577 + "x64" 578 + ], 579 + "license": "MIT", 580 + "optional": true, 581 + "os": [ 582 + "darwin" 583 + ] 584 + }, 585 + "node_modules/@cbor-extract/cbor-extract-linux-arm": { 586 + "version": "2.2.0", 587 + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.2.0.tgz", 588 + "integrity": "sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==", 589 + "cpu": [ 590 + "arm" 591 + ], 592 + "license": "MIT", 593 + "optional": true, 594 + "os": [ 595 + "linux" 596 + ] 597 + }, 598 + "node_modules/@cbor-extract/cbor-extract-linux-arm64": { 599 + "version": "2.2.0", 600 + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.2.0.tgz", 601 + "integrity": "sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==", 602 + "cpu": [ 603 + "arm64" 604 + ], 605 + "license": "MIT", 606 + "optional": true, 607 + "os": [ 608 + "linux" 609 + ] 610 + }, 611 + "node_modules/@cbor-extract/cbor-extract-linux-x64": { 612 + "version": "2.2.0", 613 + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.2.0.tgz", 614 + "integrity": "sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==", 615 + "cpu": [ 616 + "x64" 617 + ], 618 + "license": "MIT", 619 + "optional": true, 620 + "os": [ 621 + "linux" 622 + ] 623 + }, 624 + "node_modules/@cbor-extract/cbor-extract-win32-x64": { 625 + "version": "2.2.0", 626 + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.0.tgz", 627 + "integrity": "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==", 628 + "cpu": [ 629 + "x64" 630 + ], 631 + "license": "MIT", 632 + "optional": true, 633 + "os": [ 634 + "win32" 635 + ] 172 636 }, 173 637 "node_modules/@cloudflare/kv-asset-handler": { 174 638 "version": "0.3.2", ··· 998 1462 "node": ">=12" 999 1463 } 1000 1464 }, 1465 + "node_modules/@esbuild/netbsd-arm64": { 1466 + "version": "0.25.1", 1467 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", 1468 + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", 1469 + "cpu": [ 1470 + "arm64" 1471 + ], 1472 + "dev": true, 1473 + "license": "MIT", 1474 + "optional": true, 1475 + "os": [ 1476 + "netbsd" 1477 + ], 1478 + "engines": { 1479 + "node": ">=18" 1480 + } 1481 + }, 1001 1482 "node_modules/@esbuild/netbsd-x64": { 1002 1483 "version": "0.19.12", 1003 1484 "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", ··· 1012 1493 ], 1013 1494 "engines": { 1014 1495 "node": ">=12" 1496 + } 1497 + }, 1498 + "node_modules/@esbuild/openbsd-arm64": { 1499 + "version": "0.25.1", 1500 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", 1501 + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", 1502 + "cpu": [ 1503 + "arm64" 1504 + ], 1505 + "dev": true, 1506 + "license": "MIT", 1507 + "optional": true, 1508 + "os": [ 1509 + "openbsd" 1510 + ], 1511 + "engines": { 1512 + "node": ">=18" 1015 1513 } 1016 1514 }, 1017 1515 "node_modules/@esbuild/openbsd-x64": { ··· 1303 1801 "@swc/helpers": "^0.5.0" 1304 1802 } 1305 1803 }, 1804 + "node_modules/@ipld/car": { 1805 + "version": "3.2.4", 1806 + "resolved": "https://registry.npmjs.org/@ipld/car/-/car-3.2.4.tgz", 1807 + "integrity": "sha512-rezKd+jk8AsTGOoJKqzfjLJ3WVft7NZNH95f0pfPbicROvzTyvHCNy567HzSUd6gRXZ9im29z5ZEv9Hw49jSYw==", 1808 + "license": "(Apache-2.0 AND MIT)", 1809 + "dependencies": { 1810 + "@ipld/dag-cbor": "^7.0.0", 1811 + "multiformats": "^9.5.4", 1812 + "varint": "^6.0.0" 1813 + } 1814 + }, 1815 + "node_modules/@ipld/car/node_modules/multiformats": { 1816 + "version": "9.9.0", 1817 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 1818 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 1819 + "license": "(Apache-2.0 AND MIT)" 1820 + }, 1821 + "node_modules/@ipld/dag-cbor": { 1822 + "version": "7.0.3", 1823 + "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-7.0.3.tgz", 1824 + "integrity": "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA==", 1825 + "license": "(Apache-2.0 AND MIT)", 1826 + "dependencies": { 1827 + "cborg": "^1.6.0", 1828 + "multiformats": "^9.5.4" 1829 + } 1830 + }, 1831 + "node_modules/@ipld/dag-cbor/node_modules/multiformats": { 1832 + "version": "9.9.0", 1833 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 1834 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 1835 + "license": "(Apache-2.0 AND MIT)" 1836 + }, 1306 1837 "node_modules/@isaacs/cliui": { 1307 1838 "version": "8.0.2", 1308 1839 "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", ··· 1770 2301 ], 1771 2302 "engines": { 1772 2303 "node": ">= 10" 2304 + } 2305 + }, 2306 + "node_modules/@noble/curves": { 2307 + "version": "1.8.1", 2308 + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", 2309 + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", 2310 + "license": "MIT", 2311 + "dependencies": { 2312 + "@noble/hashes": "1.7.1" 2313 + }, 2314 + "engines": { 2315 + "node": "^14.21.3 || >=16" 2316 + }, 2317 + "funding": { 2318 + "url": "https://paulmillr.com/funding/" 2319 + } 2320 + }, 2321 + "node_modules/@noble/hashes": { 2322 + "version": "1.7.1", 2323 + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", 2324 + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", 2325 + "license": "MIT", 2326 + "engines": { 2327 + "node": "^14.21.3 || >=16" 2328 + }, 2329 + "funding": { 2330 + "url": "https://paulmillr.com/funding/" 1773 2331 } 1774 2332 }, 1775 2333 "node_modules/@nodelib/fs.scandir": { ··· 5444 6002 "url": "https://github.com/sponsors/ueberdosis" 5445 6003 } 5446 6004 }, 6005 + "node_modules/@ts-morph/common": { 6006 + "version": "0.17.0", 6007 + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.17.0.tgz", 6008 + "integrity": "sha512-RMSSvSfs9kb0VzkvQ2NWobwnj7TxCA9vI/IjR9bDHqgAyVbu2T0DN4wiKVqomyDWqO7dPr/tErSfq7urQ1Q37g==", 6009 + "dev": true, 6010 + "license": "MIT", 6011 + "dependencies": { 6012 + "fast-glob": "^3.2.11", 6013 + "minimatch": "^5.1.0", 6014 + "mkdirp": "^1.0.4", 6015 + "path-browserify": "^1.0.1" 6016 + } 6017 + }, 6018 + "node_modules/@ts-morph/common/node_modules/brace-expansion": { 6019 + "version": "2.0.1", 6020 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 6021 + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 6022 + "dev": true, 6023 + "license": "MIT", 6024 + "dependencies": { 6025 + "balanced-match": "^1.0.0" 6026 + } 6027 + }, 6028 + "node_modules/@ts-morph/common/node_modules/minimatch": { 6029 + "version": "5.1.6", 6030 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 6031 + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 6032 + "dev": true, 6033 + "license": "ISC", 6034 + "dependencies": { 6035 + "brace-expansion": "^2.0.1" 6036 + }, 6037 + "engines": { 6038 + "node": ">=10" 6039 + } 6040 + }, 6041 + "node_modules/@ts-morph/common/node_modules/mkdirp": { 6042 + "version": "1.0.4", 6043 + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 6044 + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 6045 + "dev": true, 6046 + "license": "MIT", 6047 + "bin": { 6048 + "mkdirp": "bin/cmd.js" 6049 + }, 6050 + "engines": { 6051 + "node": ">=10" 6052 + } 6053 + }, 5447 6054 "node_modules/@types/acorn": { 5448 6055 "version": "4.0.6", 5449 6056 "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", ··· 5773 6380 "zod": ">= 3" 5774 6381 } 5775 6382 }, 6383 + "node_modules/abort-controller": { 6384 + "version": "3.0.0", 6385 + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 6386 + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 6387 + "license": "MIT", 6388 + "dependencies": { 6389 + "event-target-shim": "^5.0.0" 6390 + }, 6391 + "engines": { 6392 + "node": ">=6.5" 6393 + } 6394 + }, 6395 + "node_modules/accepts": { 6396 + "version": "1.3.8", 6397 + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 6398 + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 6399 + "license": "MIT", 6400 + "dependencies": { 6401 + "mime-types": "~2.1.34", 6402 + "negotiator": "0.6.3" 6403 + }, 6404 + "engines": { 6405 + "node": ">= 0.6" 6406 + } 6407 + }, 5776 6408 "node_modules/acorn": { 5777 6409 "version": "8.11.3", 5778 6410 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", ··· 5919 6551 "funding": { 5920 6552 "url": "https://github.com/sponsors/ljharb" 5921 6553 } 6554 + }, 6555 + "node_modules/array-flatten": { 6556 + "version": "1.1.1", 6557 + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 6558 + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", 6559 + "license": "MIT" 5922 6560 }, 5923 6561 "node_modules/array-includes": { 5924 6562 "version": "3.1.8", ··· 6100 6738 "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 6101 6739 "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 6102 6740 }, 6741 + "node_modules/atomic-sleep": { 6742 + "version": "1.0.0", 6743 + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", 6744 + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", 6745 + "license": "MIT", 6746 + "engines": { 6747 + "node": ">=8.0.0" 6748 + } 6749 + }, 6103 6750 "node_modules/autoprefixer": { 6104 6751 "version": "10.4.19", 6105 6752 "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", ··· 6254 6901 "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", 6255 6902 "dev": true 6256 6903 }, 6904 + "node_modules/body-parser": { 6905 + "version": "1.20.3", 6906 + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", 6907 + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", 6908 + "license": "MIT", 6909 + "dependencies": { 6910 + "bytes": "3.1.2", 6911 + "content-type": "~1.0.5", 6912 + "debug": "2.6.9", 6913 + "depd": "2.0.0", 6914 + "destroy": "1.2.0", 6915 + "http-errors": "2.0.0", 6916 + "iconv-lite": "0.4.24", 6917 + "on-finished": "2.4.1", 6918 + "qs": "6.13.0", 6919 + "raw-body": "2.5.2", 6920 + "type-is": "~1.6.18", 6921 + "unpipe": "1.0.0" 6922 + }, 6923 + "engines": { 6924 + "node": ">= 0.8", 6925 + "npm": "1.2.8000 || >= 1.4.16" 6926 + } 6927 + }, 6928 + "node_modules/body-parser/node_modules/debug": { 6929 + "version": "2.6.9", 6930 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 6931 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 6932 + "license": "MIT", 6933 + "dependencies": { 6934 + "ms": "2.0.0" 6935 + } 6936 + }, 6937 + "node_modules/body-parser/node_modules/ms": { 6938 + "version": "2.0.0", 6939 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 6940 + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 6941 + "license": "MIT" 6942 + }, 6943 + "node_modules/body-parser/node_modules/qs": { 6944 + "version": "6.13.0", 6945 + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 6946 + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 6947 + "license": "BSD-3-Clause", 6948 + "dependencies": { 6949 + "side-channel": "^1.0.6" 6950 + }, 6951 + "engines": { 6952 + "node": ">=0.6" 6953 + }, 6954 + "funding": { 6955 + "url": "https://github.com/sponsors/ljharb" 6956 + } 6957 + }, 6257 6958 "node_modules/brace-expansion": { 6258 6959 "version": "1.1.11", 6259 6960 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", ··· 6308 7009 "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 6309 7010 } 6310 7011 }, 7012 + "node_modules/buffer": { 7013 + "version": "6.0.3", 7014 + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 7015 + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 7016 + "funding": [ 7017 + { 7018 + "type": "github", 7019 + "url": "https://github.com/sponsors/feross" 7020 + }, 7021 + { 7022 + "type": "patreon", 7023 + "url": "https://www.patreon.com/feross" 7024 + }, 7025 + { 7026 + "type": "consulting", 7027 + "url": "https://feross.org/support" 7028 + } 7029 + ], 7030 + "license": "MIT", 7031 + "dependencies": { 7032 + "base64-js": "^1.3.1", 7033 + "ieee754": "^1.2.1" 7034 + } 7035 + }, 6311 7036 "node_modules/buffer-equal-constant-time": { 6312 7037 "version": "1.0.1", 6313 7038 "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", ··· 6329 7054 }, 6330 7055 "engines": { 6331 7056 "node": ">=10.16.0" 7057 + } 7058 + }, 7059 + "node_modules/bytes": { 7060 + "version": "3.1.2", 7061 + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 7062 + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 7063 + "license": "MIT", 7064 + "engines": { 7065 + "node": ">= 0.8" 6332 7066 } 6333 7067 }, 6334 7068 "node_modules/call-bind": { ··· 6394 7128 "dependencies": { 6395 7129 "debug": "^4.3.1", 6396 7130 "tslib": "^2.2.0" 7131 + } 7132 + }, 7133 + "node_modules/cbor-extract": { 7134 + "version": "2.2.0", 7135 + "resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.2.0.tgz", 7136 + "integrity": "sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==", 7137 + "hasInstallScript": true, 7138 + "license": "MIT", 7139 + "optional": true, 7140 + "dependencies": { 7141 + "node-gyp-build-optional-packages": "5.1.1" 7142 + }, 7143 + "bin": { 7144 + "download-cbor-prebuilds": "bin/download-prebuilds.js" 7145 + }, 7146 + "optionalDependencies": { 7147 + "@cbor-extract/cbor-extract-darwin-arm64": "2.2.0", 7148 + "@cbor-extract/cbor-extract-darwin-x64": "2.2.0", 7149 + "@cbor-extract/cbor-extract-linux-arm": "2.2.0", 7150 + "@cbor-extract/cbor-extract-linux-arm64": "2.2.0", 7151 + "@cbor-extract/cbor-extract-linux-x64": "2.2.0", 7152 + "@cbor-extract/cbor-extract-win32-x64": "2.2.0" 7153 + } 7154 + }, 7155 + "node_modules/cbor-x": { 7156 + "version": "1.6.0", 7157 + "resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.6.0.tgz", 7158 + "integrity": "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==", 7159 + "license": "MIT", 7160 + "optionalDependencies": { 7161 + "cbor-extract": "^2.2.0" 7162 + } 7163 + }, 7164 + "node_modules/cborg": { 7165 + "version": "1.10.2", 7166 + "resolved": "https://registry.npmjs.org/cborg/-/cborg-1.10.2.tgz", 7167 + "integrity": "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug==", 7168 + "license": "Apache-2.0", 7169 + "bin": { 7170 + "cborg": "cli.js" 6397 7171 } 6398 7172 }, 6399 7173 "node_modules/ccount": { ··· 6540 7314 "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 6541 7315 } 6542 7316 }, 7317 + "node_modules/code-block-writer": { 7318 + "version": "11.0.3", 7319 + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", 7320 + "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", 7321 + "dev": true, 7322 + "license": "MIT" 7323 + }, 6543 7324 "node_modules/collapse-white-space": { 6544 7325 "version": "2.1.0", 6545 7326 "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", ··· 6607 7388 "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 6608 7389 "dev": true 6609 7390 }, 7391 + "node_modules/content-disposition": { 7392 + "version": "0.5.4", 7393 + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 7394 + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 7395 + "license": "MIT", 7396 + "dependencies": { 7397 + "safe-buffer": "5.2.1" 7398 + }, 7399 + "engines": { 7400 + "node": ">= 0.6" 7401 + } 7402 + }, 7403 + "node_modules/content-type": { 7404 + "version": "1.0.5", 7405 + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 7406 + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 7407 + "license": "MIT", 7408 + "engines": { 7409 + "node": ">= 0.6" 7410 + } 7411 + }, 6610 7412 "node_modules/cookie": { 6611 7413 "version": "0.5.0", 6612 7414 "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", ··· 6614 7416 "engines": { 6615 7417 "node": ">= 0.6" 6616 7418 } 7419 + }, 7420 + "node_modules/cookie-signature": { 7421 + "version": "1.0.6", 7422 + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 7423 + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", 7424 + "license": "MIT" 6617 7425 }, 6618 7426 "node_modules/crelt": { 6619 7427 "version": "1.0.6", ··· 6832 7640 "node": ">=0.4.0" 6833 7641 } 6834 7642 }, 7643 + "node_modules/depd": { 7644 + "version": "2.0.0", 7645 + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 7646 + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 7647 + "license": "MIT", 7648 + "engines": { 7649 + "node": ">= 0.8" 7650 + } 7651 + }, 6835 7652 "node_modules/dequal": { 6836 7653 "version": "2.0.3", 6837 7654 "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", 6838 7655 "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", 6839 7656 "engines": { 6840 7657 "node": ">=6" 7658 + } 7659 + }, 7660 + "node_modules/destroy": { 7661 + "version": "1.2.0", 7662 + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 7663 + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 7664 + "license": "MIT", 7665 + "engines": { 7666 + "node": ">= 0.8", 7667 + "npm": "1.2.8000 || >= 1.4.16" 7668 + } 7669 + }, 7670 + "node_modules/detect-libc": { 7671 + "version": "2.0.3", 7672 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", 7673 + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", 7674 + "license": "Apache-2.0", 7675 + "optional": true, 7676 + "engines": { 7677 + "node": ">=8" 6841 7678 } 6842 7679 }, 6843 7680 "node_modules/detect-node-es": { ··· 7061 7898 "safe-buffer": "^5.0.1" 7062 7899 } 7063 7900 }, 7901 + "node_modules/ee-first": { 7902 + "version": "1.1.1", 7903 + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 7904 + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", 7905 + "license": "MIT" 7906 + }, 7064 7907 "node_modules/electron-to-chromium": { 7065 7908 "version": "1.4.783", 7066 7909 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.783.tgz", ··· 7073 7916 "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 7074 7917 "dev": true 7075 7918 }, 7919 + "node_modules/encodeurl": { 7920 + "version": "2.0.0", 7921 + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 7922 + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 7923 + "license": "MIT", 7924 + "engines": { 7925 + "node": ">= 0.8" 7926 + } 7927 + }, 7076 7928 "node_modules/enhanced-resolve": { 7077 7929 "version": "5.16.1", 7078 7930 "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", ··· 7405 8257 "engines": { 7406 8258 "node": ">=6" 7407 8259 } 8260 + }, 8261 + "node_modules/escape-html": { 8262 + "version": "1.0.3", 8263 + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 8264 + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", 8265 + "license": "MIT" 7408 8266 }, 7409 8267 "node_modules/escape-string-regexp": { 7410 8268 "version": "4.0.0", ··· 7942 8800 "node": ">=0.10.0" 7943 8801 } 7944 8802 }, 8803 + "node_modules/etag": { 8804 + "version": "1.8.1", 8805 + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 8806 + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 8807 + "license": "MIT", 8808 + "engines": { 8809 + "node": ">= 0.6" 8810 + } 8811 + }, 7945 8812 "node_modules/event-emitter": { 7946 8813 "version": "0.3.5", 7947 8814 "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", ··· 7952 8819 "es5-ext": "~0.10.14" 7953 8820 } 7954 8821 }, 8822 + "node_modules/event-target-shim": { 8823 + "version": "5.0.1", 8824 + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 8825 + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", 8826 + "license": "MIT", 8827 + "engines": { 8828 + "node": ">=6" 8829 + } 8830 + }, 8831 + "node_modules/eventemitter3": { 8832 + "version": "4.0.7", 8833 + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 8834 + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", 8835 + "license": "MIT" 8836 + }, 8837 + "node_modules/events": { 8838 + "version": "3.3.0", 8839 + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 8840 + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", 8841 + "license": "MIT", 8842 + "engines": { 8843 + "node": ">=0.8.x" 8844 + } 8845 + }, 7955 8846 "node_modules/exit-hook": { 7956 8847 "version": "2.2.1", 7957 8848 "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", ··· 7964 8855 "url": "https://github.com/sponsors/sindresorhus" 7965 8856 } 7966 8857 }, 8858 + "node_modules/express": { 8859 + "version": "4.21.2", 8860 + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", 8861 + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", 8862 + "license": "MIT", 8863 + "dependencies": { 8864 + "accepts": "~1.3.8", 8865 + "array-flatten": "1.1.1", 8866 + "body-parser": "1.20.3", 8867 + "content-disposition": "0.5.4", 8868 + "content-type": "~1.0.4", 8869 + "cookie": "0.7.1", 8870 + "cookie-signature": "1.0.6", 8871 + "debug": "2.6.9", 8872 + "depd": "2.0.0", 8873 + "encodeurl": "~2.0.0", 8874 + "escape-html": "~1.0.3", 8875 + "etag": "~1.8.1", 8876 + "finalhandler": "1.3.1", 8877 + "fresh": "0.5.2", 8878 + "http-errors": "2.0.0", 8879 + "merge-descriptors": "1.0.3", 8880 + "methods": "~1.1.2", 8881 + "on-finished": "2.4.1", 8882 + "parseurl": "~1.3.3", 8883 + "path-to-regexp": "0.1.12", 8884 + "proxy-addr": "~2.0.7", 8885 + "qs": "6.13.0", 8886 + "range-parser": "~1.2.1", 8887 + "safe-buffer": "5.2.1", 8888 + "send": "0.19.0", 8889 + "serve-static": "1.16.2", 8890 + "setprototypeof": "1.2.0", 8891 + "statuses": "2.0.1", 8892 + "type-is": "~1.6.18", 8893 + "utils-merge": "1.0.1", 8894 + "vary": "~1.1.2" 8895 + }, 8896 + "engines": { 8897 + "node": ">= 0.10.0" 8898 + }, 8899 + "funding": { 8900 + "type": "opencollective", 8901 + "url": "https://opencollective.com/express" 8902 + } 8903 + }, 8904 + "node_modules/express/node_modules/cookie": { 8905 + "version": "0.7.1", 8906 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", 8907 + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", 8908 + "license": "MIT", 8909 + "engines": { 8910 + "node": ">= 0.6" 8911 + } 8912 + }, 8913 + "node_modules/express/node_modules/debug": { 8914 + "version": "2.6.9", 8915 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 8916 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 8917 + "license": "MIT", 8918 + "dependencies": { 8919 + "ms": "2.0.0" 8920 + } 8921 + }, 8922 + "node_modules/express/node_modules/ms": { 8923 + "version": "2.0.0", 8924 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 8925 + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 8926 + "license": "MIT" 8927 + }, 8928 + "node_modules/express/node_modules/path-to-regexp": { 8929 + "version": "0.1.12", 8930 + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", 8931 + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", 8932 + "license": "MIT" 8933 + }, 8934 + "node_modules/express/node_modules/qs": { 8935 + "version": "6.13.0", 8936 + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 8937 + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 8938 + "license": "BSD-3-Clause", 8939 + "dependencies": { 8940 + "side-channel": "^1.0.6" 8941 + }, 8942 + "engines": { 8943 + "node": ">=0.6" 8944 + }, 8945 + "funding": { 8946 + "url": "https://github.com/sponsors/ljharb" 8947 + } 8948 + }, 7967 8949 "node_modules/ext": { 7968 8950 "version": "1.7.0", 7969 8951 "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", ··· 8017 8999 "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 8018 9000 "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 8019 9001 "dev": true 9002 + }, 9003 + "node_modules/fast-redact": { 9004 + "version": "3.5.0", 9005 + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", 9006 + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", 9007 + "license": "MIT", 9008 + "engines": { 9009 + "node": ">=6" 9010 + } 8020 9011 }, 8021 9012 "node_modules/fast-uri": { 8022 9013 "version": "3.0.5", ··· 8091 9082 "node": ">=8" 8092 9083 } 8093 9084 }, 9085 + "node_modules/finalhandler": { 9086 + "version": "1.3.1", 9087 + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", 9088 + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", 9089 + "license": "MIT", 9090 + "dependencies": { 9091 + "debug": "2.6.9", 9092 + "encodeurl": "~2.0.0", 9093 + "escape-html": "~1.0.3", 9094 + "on-finished": "2.4.1", 9095 + "parseurl": "~1.3.3", 9096 + "statuses": "2.0.1", 9097 + "unpipe": "~1.0.0" 9098 + }, 9099 + "engines": { 9100 + "node": ">= 0.8" 9101 + } 9102 + }, 9103 + "node_modules/finalhandler/node_modules/debug": { 9104 + "version": "2.6.9", 9105 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 9106 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 9107 + "license": "MIT", 9108 + "dependencies": { 9109 + "ms": "2.0.0" 9110 + } 9111 + }, 9112 + "node_modules/finalhandler/node_modules/ms": { 9113 + "version": "2.0.0", 9114 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 9115 + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 9116 + "license": "MIT" 9117 + }, 8094 9118 "node_modules/find-up": { 8095 9119 "version": "5.0.0", 8096 9120 "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", ··· 8196 9220 "node": ">=12.20.0" 8197 9221 } 8198 9222 }, 9223 + "node_modules/forwarded": { 9224 + "version": "0.2.0", 9225 + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 9226 + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 9227 + "license": "MIT", 9228 + "engines": { 9229 + "node": ">= 0.6" 9230 + } 9231 + }, 8199 9232 "node_modules/fraction.js": { 8200 9233 "version": "4.3.7", 8201 9234 "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", ··· 8215 9248 "integrity": "sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ==", 8216 9249 "engines": { 8217 9250 "node": "^14.13.1 || >=16.0.0" 9251 + } 9252 + }, 9253 + "node_modules/fresh": { 9254 + "version": "0.5.2", 9255 + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 9256 + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 9257 + "license": "MIT", 9258 + "engines": { 9259 + "node": ">= 0.6" 8218 9260 } 8219 9261 }, 8220 9262 "node_modules/fs.realpath": { ··· 8888 9930 "url": "https://github.com/sponsors/wooorm" 8889 9931 } 8890 9932 }, 9933 + "node_modules/http-errors": { 9934 + "version": "2.0.0", 9935 + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 9936 + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 9937 + "license": "MIT", 9938 + "dependencies": { 9939 + "depd": "2.0.0", 9940 + "inherits": "2.0.4", 9941 + "setprototypeof": "1.2.0", 9942 + "statuses": "2.0.1", 9943 + "toidentifier": "1.0.1" 9944 + }, 9945 + "engines": { 9946 + "node": ">= 0.8" 9947 + } 9948 + }, 8891 9949 "node_modules/https-proxy-agent": { 8892 9950 "version": "7.0.4", 8893 9951 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", ··· 8901 9959 "node": ">= 14" 8902 9960 } 8903 9961 }, 9962 + "node_modules/iconv-lite": { 9963 + "version": "0.4.24", 9964 + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 9965 + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 9966 + "license": "MIT", 9967 + "dependencies": { 9968 + "safer-buffer": ">= 2.1.2 < 3" 9969 + }, 9970 + "engines": { 9971 + "node": ">=0.10.0" 9972 + } 9973 + }, 9974 + "node_modules/ieee754": { 9975 + "version": "1.2.1", 9976 + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 9977 + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 9978 + "funding": [ 9979 + { 9980 + "type": "github", 9981 + "url": "https://github.com/sponsors/feross" 9982 + }, 9983 + { 9984 + "type": "patreon", 9985 + "url": "https://www.patreon.com/feross" 9986 + }, 9987 + { 9988 + "type": "consulting", 9989 + "url": "https://feross.org/support" 9990 + } 9991 + ], 9992 + "license": "BSD-3-Clause" 9993 + }, 8904 9994 "node_modules/ignore": { 8905 9995 "version": "5.3.1", 8906 9996 "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", ··· 8960 10050 "node_modules/inherits": { 8961 10051 "version": "2.0.4", 8962 10052 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 8963 - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 8964 - "dev": true 10053 + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 8965 10054 }, 8966 10055 "node_modules/inline-style-parser": { 8967 10056 "version": "0.2.4", ··· 9001 10090 "loose-envify": "^1.0.0" 9002 10091 } 9003 10092 }, 10093 + "node_modules/ipaddr.js": { 10094 + "version": "2.2.0", 10095 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", 10096 + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", 10097 + "license": "MIT", 10098 + "engines": { 10099 + "node": ">= 10" 10100 + } 10101 + }, 9004 10102 "node_modules/is-alphabetical": { 9005 10103 "version": "2.0.1", 9006 10104 "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", ··· 9492 10590 "jiti": "bin/jiti.js" 9493 10591 } 9494 10592 }, 10593 + "node_modules/jose": { 10594 + "version": "5.9.6", 10595 + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", 10596 + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", 10597 + "license": "MIT", 10598 + "funding": { 10599 + "url": "https://github.com/sponsors/panva" 10600 + } 10601 + }, 9495 10602 "node_modules/js-tokens": { 9496 10603 "version": "4.0.0", 9497 10604 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", ··· 9799 10906 "version": "10.2.2", 9800 10907 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", 9801 10908 "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", 9802 - "dev": true, 9803 10909 "engines": { 9804 10910 "node": "14 || >=16.14" 9805 10911 } ··· 10148 11254 "license": "MIT", 10149 11255 "peer": true 10150 11256 }, 11257 + "node_modules/media-typer": { 11258 + "version": "0.3.0", 11259 + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 11260 + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 11261 + "license": "MIT", 11262 + "engines": { 11263 + "node": ">= 0.6" 11264 + } 11265 + }, 10151 11266 "node_modules/memoizee": { 10152 11267 "version": "0.4.17", 10153 11268 "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", ··· 10167 11282 "node": ">=0.12" 10168 11283 } 10169 11284 }, 11285 + "node_modules/merge-descriptors": { 11286 + "version": "1.0.3", 11287 + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", 11288 + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", 11289 + "license": "MIT", 11290 + "funding": { 11291 + "url": "https://github.com/sponsors/sindresorhus" 11292 + } 11293 + }, 10170 11294 "node_modules/merge2": { 10171 11295 "version": "1.4.1", 10172 11296 "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", ··· 10174 11298 "dev": true, 10175 11299 "engines": { 10176 11300 "node": ">= 8" 11301 + } 11302 + }, 11303 + "node_modules/methods": { 11304 + "version": "1.1.2", 11305 + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 11306 + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 11307 + "license": "MIT", 11308 + "engines": { 11309 + "node": ">= 0.6" 10177 11310 } 10178 11311 }, 10179 11312 "node_modules/micromark": { ··· 11083 12216 "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 11084 12217 }, 11085 12218 "node_modules/multiformats": { 11086 - "version": "9.9.0", 11087 - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 11088 - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 11089 - "license": "(Apache-2.0 AND MIT)" 12219 + "version": "13.3.2", 12220 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.3.2.tgz", 12221 + "integrity": "sha512-qbB0CQDt3QKfiAzZ5ZYjLFOs+zW43vA4uyM8g27PeEuXZybUOFyjrVdP93HPBHMoglibwfkdVwbzfUq8qGcH6g==", 12222 + "license": "Apache-2.0 OR MIT" 11090 12223 }, 11091 12224 "node_modules/mustache": { 11092 12225 "version": "4.2.0", ··· 11130 12263 "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 11131 12264 "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 11132 12265 "dev": true 12266 + }, 12267 + "node_modules/negotiator": { 12268 + "version": "0.6.3", 12269 + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 12270 + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 12271 + "license": "MIT", 12272 + "engines": { 12273 + "node": ">= 0.6" 12274 + } 11133 12275 }, 11134 12276 "node_modules/next": { 11135 12277 "version": "14.2.4", ··· 11290 12432 "node": ">= 6.13.0" 11291 12433 } 11292 12434 }, 12435 + "node_modules/node-gyp-build-optional-packages": { 12436 + "version": "5.1.1", 12437 + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", 12438 + "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", 12439 + "license": "MIT", 12440 + "optional": true, 12441 + "dependencies": { 12442 + "detect-libc": "^2.0.1" 12443 + }, 12444 + "bin": { 12445 + "node-gyp-build-optional-packages": "bin.js", 12446 + "node-gyp-build-optional-packages-optional": "optional.js", 12447 + "node-gyp-build-optional-packages-test": "build-test.js" 12448 + } 12449 + }, 11293 12450 "node_modules/node-releases": { 11294 12451 "version": "2.0.14", 11295 12452 "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", ··· 11456 12613 "url": "https://github.com/sponsors/ljharb" 11457 12614 } 11458 12615 }, 12616 + "node_modules/on-exit-leak-free": { 12617 + "version": "2.1.2", 12618 + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", 12619 + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", 12620 + "license": "MIT", 12621 + "engines": { 12622 + "node": ">=14.0.0" 12623 + } 12624 + }, 12625 + "node_modules/on-finished": { 12626 + "version": "2.4.1", 12627 + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 12628 + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 12629 + "license": "MIT", 12630 + "dependencies": { 12631 + "ee-first": "1.1.1" 12632 + }, 12633 + "engines": { 12634 + "node": ">= 0.8" 12635 + } 12636 + }, 11459 12637 "node_modules/once": { 11460 12638 "version": "1.4.0", 11461 12639 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", ··· 11487 12665 "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", 11488 12666 "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==" 11489 12667 }, 12668 + "node_modules/p-finally": { 12669 + "version": "1.0.0", 12670 + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 12671 + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", 12672 + "license": "MIT", 12673 + "engines": { 12674 + "node": ">=4" 12675 + } 12676 + }, 11490 12677 "node_modules/p-limit": { 11491 12678 "version": "3.1.0", 11492 12679 "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", ··· 11517 12704 "url": "https://github.com/sponsors/sindresorhus" 11518 12705 } 11519 12706 }, 12707 + "node_modules/p-queue": { 12708 + "version": "6.6.2", 12709 + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", 12710 + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", 12711 + "license": "MIT", 12712 + "dependencies": { 12713 + "eventemitter3": "^4.0.4", 12714 + "p-timeout": "^3.2.0" 12715 + }, 12716 + "engines": { 12717 + "node": ">=8" 12718 + }, 12719 + "funding": { 12720 + "url": "https://github.com/sponsors/sindresorhus" 12721 + } 12722 + }, 12723 + "node_modules/p-timeout": { 12724 + "version": "3.2.0", 12725 + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", 12726 + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", 12727 + "license": "MIT", 12728 + "dependencies": { 12729 + "p-finally": "^1.0.0" 12730 + }, 12731 + "engines": { 12732 + "node": ">=8" 12733 + } 12734 + }, 11520 12735 "node_modules/package-json-from-dist": { 11521 12736 "version": "1.0.0", 11522 12737 "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", ··· 11569 12784 "funding": { 11570 12785 "url": "https://github.com/inikulin/parse5?sponsor=1" 11571 12786 } 12787 + }, 12788 + "node_modules/parseurl": { 12789 + "version": "1.3.3", 12790 + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 12791 + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 12792 + "license": "MIT", 12793 + "engines": { 12794 + "node": ">= 0.8" 12795 + } 12796 + }, 12797 + "node_modules/path-browserify": { 12798 + "version": "1.0.1", 12799 + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", 12800 + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", 12801 + "dev": true, 12802 + "license": "MIT" 11572 12803 }, 11573 12804 "node_modules/path-exists": { 11574 12805 "version": "4.0.0", ··· 11660 12891 "node": ">=0.10.0" 11661 12892 } 11662 12893 }, 12894 + "node_modules/pino": { 12895 + "version": "8.21.0", 12896 + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", 12897 + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", 12898 + "license": "MIT", 12899 + "dependencies": { 12900 + "atomic-sleep": "^1.0.0", 12901 + "fast-redact": "^3.1.1", 12902 + "on-exit-leak-free": "^2.1.0", 12903 + "pino-abstract-transport": "^1.2.0", 12904 + "pino-std-serializers": "^6.0.0", 12905 + "process-warning": "^3.0.0", 12906 + "quick-format-unescaped": "^4.0.3", 12907 + "real-require": "^0.2.0", 12908 + "safe-stable-stringify": "^2.3.1", 12909 + "sonic-boom": "^3.7.0", 12910 + "thread-stream": "^2.6.0" 12911 + }, 12912 + "bin": { 12913 + "pino": "bin.js" 12914 + } 12915 + }, 12916 + "node_modules/pino-abstract-transport": { 12917 + "version": "1.2.0", 12918 + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", 12919 + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", 12920 + "license": "MIT", 12921 + "dependencies": { 12922 + "readable-stream": "^4.0.0", 12923 + "split2": "^4.0.0" 12924 + } 12925 + }, 12926 + "node_modules/pino-std-serializers": { 12927 + "version": "6.2.2", 12928 + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", 12929 + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", 12930 + "license": "MIT" 12931 + }, 11663 12932 "node_modules/pirates": { 11664 12933 "version": "4.0.6", 11665 12934 "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", ··· 11869 13138 "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", 11870 13139 "dev": true 11871 13140 }, 13141 + "node_modules/process": { 13142 + "version": "0.11.10", 13143 + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 13144 + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", 13145 + "license": "MIT", 13146 + "engines": { 13147 + "node": ">= 0.6.0" 13148 + } 13149 + }, 13150 + "node_modules/process-warning": { 13151 + "version": "3.0.0", 13152 + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", 13153 + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", 13154 + "license": "MIT" 13155 + }, 11872 13156 "node_modules/prop-types": { 11873 13157 "version": "15.8.1", 11874 13158 "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", ··· 11977 13261 } 11978 13262 }, 11979 13263 "node_modules/prosemirror-markdown": { 11980 - "version": "1.13.1", 11981 - "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.1.tgz", 11982 - "integrity": "sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==", 13264 + "version": "1.13.2", 13265 + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz", 13266 + "integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==", 11983 13267 "license": "MIT", 11984 13268 "peer": true, 11985 13269 "dependencies": { 11986 13270 "@types/markdown-it": "^14.0.0", 11987 13271 "markdown-it": "^14.0.0", 11988 - "prosemirror-model": "^1.20.0" 13272 + "prosemirror-model": "^1.25.0" 11989 13273 } 11990 13274 }, 11991 13275 "node_modules/prosemirror-menu": { ··· 12002 13286 } 12003 13287 }, 12004 13288 "node_modules/prosemirror-model": { 12005 - "version": "1.24.1", 12006 - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.24.1.tgz", 12007 - "integrity": "sha512-YM053N+vTThzlWJ/AtPtF1j0ebO36nvbmDy4U7qA2XQB8JVaQp1FmB9Jhrps8s+z+uxhhVTny4m20ptUvhk0Mg==", 13289 + "version": "1.25.0", 13290 + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.0.tgz", 13291 + "integrity": "sha512-/8XUmxWf0pkj2BmtqZHYJipTBMHIdVjuvFzMvEoxrtyGNmfvdhBiRwYt/eFwy2wA9DtBW3RLqvZnjurEkHaFCw==", 12008 13292 "license": "MIT", 12009 13293 "dependencies": { 12010 13294 "orderedmap": "^2.0.0" 12011 13295 } 12012 13296 }, 12013 13297 "node_modules/prosemirror-schema-basic": { 12014 - "version": "1.2.3", 12015 - "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz", 12016 - "integrity": "sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==", 13298 + "version": "1.2.4", 13299 + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", 13300 + "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", 12017 13301 "license": "MIT", 12018 13302 "dependencies": { 12019 - "prosemirror-model": "^1.19.0" 13303 + "prosemirror-model": "^1.25.0" 12020 13304 } 12021 13305 }, 12022 13306 "node_modules/prosemirror-schema-list": { 12023 - "version": "1.5.0", 12024 - "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.0.tgz", 12025 - "integrity": "sha512-gg1tAfH1sqpECdhIHOA/aLg2VH3ROKBWQ4m8Qp9mBKrOxQRW61zc+gMCI8nh22gnBzd1t2u1/NPLmO3nAa3ssg==", 13307 + "version": "1.5.1", 13308 + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", 13309 + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", 12026 13310 "license": "MIT", 12027 13311 "peer": true, 12028 13312 "dependencies": { ··· 12072 13356 } 12073 13357 }, 12074 13358 "node_modules/prosemirror-transform": { 12075 - "version": "1.10.2", 12076 - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.2.tgz", 12077 - "integrity": "sha512-2iUq0wv2iRoJO/zj5mv8uDUriOHWzXRnOTVgCzSXnktS/2iQRa3UUQwVlkBlYZFtygw6Nh1+X4mGqoYBINn5KQ==", 13359 + "version": "1.10.3", 13360 + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.3.tgz", 13361 + "integrity": "sha512-Nhh/+1kZGRINbEHmVu39oynhcap4hWTs/BlU7NnxWj3+l0qi8I1mu67v6mMdEe/ltD8hHvU4FV6PHiCw2VSpMw==", 12078 13362 "license": "MIT", 12079 13363 "dependencies": { 12080 13364 "prosemirror-model": "^1.21.0" 12081 13365 } 12082 13366 }, 12083 13367 "node_modules/prosemirror-view": { 12084 - "version": "1.38.0", 12085 - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.38.0.tgz", 12086 - "integrity": "sha512-O45kxXQTaP9wPdXhp8TKqCR+/unS/gnfg9Q93svQcB3j0mlp2XSPAmsPefxHADwzC+fbNS404jqRxm3UQaGvgw==", 13368 + "version": "1.38.1", 13369 + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.38.1.tgz", 13370 + "integrity": "sha512-4FH/uM1A4PNyrxXbD+RAbAsf0d/mM0D/wAKSVVWK7o0A9Q/oOXJBrw786mBf2Vnrs/Edly6dH6Z2gsb7zWwaUw==", 12087 13371 "license": "MIT", 12088 13372 "dependencies": { 12089 13373 "prosemirror-model": "^1.20.0", ··· 12091 13375 "prosemirror-transform": "^1.1.0" 12092 13376 } 12093 13377 }, 13378 + "node_modules/proxy-addr": { 13379 + "version": "2.0.7", 13380 + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 13381 + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 13382 + "license": "MIT", 13383 + "dependencies": { 13384 + "forwarded": "0.2.0", 13385 + "ipaddr.js": "1.9.1" 13386 + }, 13387 + "engines": { 13388 + "node": ">= 0.10" 13389 + } 13390 + }, 13391 + "node_modules/proxy-addr/node_modules/ipaddr.js": { 13392 + "version": "1.9.1", 13393 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 13394 + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 13395 + "license": "MIT", 13396 + "engines": { 13397 + "node": ">= 0.10" 13398 + } 13399 + }, 12094 13400 "node_modules/proxy-from-env": { 12095 13401 "version": "1.1.0", 12096 13402 "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 12097 13403 "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 13404 + }, 13405 + "node_modules/psl": { 13406 + "version": "1.15.0", 13407 + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", 13408 + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", 13409 + "license": "MIT", 13410 + "dependencies": { 13411 + "punycode": "^2.3.1" 13412 + }, 13413 + "funding": { 13414 + "url": "https://github.com/sponsors/lupomontero" 13415 + } 12098 13416 }, 12099 13417 "node_modules/punycode": { 12100 13418 "version": "2.3.1", ··· 12150 13468 } 12151 13469 ] 12152 13470 }, 13471 + "node_modules/quick-format-unescaped": { 13472 + "version": "4.0.4", 13473 + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", 13474 + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", 13475 + "license": "MIT" 13476 + }, 12153 13477 "node_modules/ramda": { 12154 13478 "version": "0.29.1", 12155 13479 "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", ··· 12159 13483 "url": "https://opencollective.com/ramda" 12160 13484 } 12161 13485 }, 13486 + "node_modules/range-parser": { 13487 + "version": "1.2.1", 13488 + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 13489 + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 13490 + "license": "MIT", 13491 + "engines": { 13492 + "node": ">= 0.6" 13493 + } 13494 + }, 13495 + "node_modules/rate-limiter-flexible": { 13496 + "version": "2.4.2", 13497 + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.4.2.tgz", 13498 + "integrity": "sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw==", 13499 + "license": "ISC" 13500 + }, 13501 + "node_modules/raw-body": { 13502 + "version": "2.5.2", 13503 + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", 13504 + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", 13505 + "license": "MIT", 13506 + "dependencies": { 13507 + "bytes": "3.1.2", 13508 + "http-errors": "2.0.0", 13509 + "iconv-lite": "0.4.24", 13510 + "unpipe": "1.0.0" 13511 + }, 13512 + "engines": { 13513 + "node": ">= 0.8" 13514 + } 13515 + }, 12162 13516 "node_modules/react": { 12163 13517 "version": "18.3.1", 12164 13518 "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", ··· 12419 13773 "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 12420 13774 } 12421 13775 }, 13776 + "node_modules/readable-stream": { 13777 + "version": "4.7.0", 13778 + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", 13779 + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", 13780 + "license": "MIT", 13781 + "dependencies": { 13782 + "abort-controller": "^3.0.0", 13783 + "buffer": "^6.0.3", 13784 + "events": "^3.3.0", 13785 + "process": "^0.11.10", 13786 + "string_decoder": "^1.3.0" 13787 + }, 13788 + "engines": { 13789 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 13790 + } 13791 + }, 12422 13792 "node_modules/readdirp": { 12423 13793 "version": "3.6.0", 12424 13794 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", ··· 12429 13799 }, 12430 13800 "engines": { 12431 13801 "node": ">=8.10.0" 13802 + } 13803 + }, 13804 + "node_modules/real-require": { 13805 + "version": "0.2.0", 13806 + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", 13807 + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", 13808 + "license": "MIT", 13809 + "engines": { 13810 + "node": ">= 12.13.0" 12432 13811 } 12433 13812 }, 12434 13813 "node_modules/recma-build-jsx": { ··· 12926 14305 "url": "https://github.com/sponsors/ljharb" 12927 14306 } 12928 14307 }, 14308 + "node_modules/safe-stable-stringify": { 14309 + "version": "2.5.0", 14310 + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", 14311 + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", 14312 + "license": "MIT", 14313 + "engines": { 14314 + "node": ">=10" 14315 + } 14316 + }, 14317 + "node_modules/safer-buffer": { 14318 + "version": "2.1.2", 14319 + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 14320 + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 14321 + "license": "MIT" 14322 + }, 12929 14323 "node_modules/scheduler": { 12930 14324 "version": "0.23.2", 12931 14325 "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", ··· 12964 14358 "node": ">=10" 12965 14359 } 12966 14360 }, 14361 + "node_modules/send": { 14362 + "version": "0.19.0", 14363 + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", 14364 + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 14365 + "license": "MIT", 14366 + "dependencies": { 14367 + "debug": "2.6.9", 14368 + "depd": "2.0.0", 14369 + "destroy": "1.2.0", 14370 + "encodeurl": "~1.0.2", 14371 + "escape-html": "~1.0.3", 14372 + "etag": "~1.8.1", 14373 + "fresh": "0.5.2", 14374 + "http-errors": "2.0.0", 14375 + "mime": "1.6.0", 14376 + "ms": "2.1.3", 14377 + "on-finished": "2.4.1", 14378 + "range-parser": "~1.2.1", 14379 + "statuses": "2.0.1" 14380 + }, 14381 + "engines": { 14382 + "node": ">= 0.8.0" 14383 + } 14384 + }, 14385 + "node_modules/send/node_modules/debug": { 14386 + "version": "2.6.9", 14387 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 14388 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 14389 + "license": "MIT", 14390 + "dependencies": { 14391 + "ms": "2.0.0" 14392 + } 14393 + }, 14394 + "node_modules/send/node_modules/debug/node_modules/ms": { 14395 + "version": "2.0.0", 14396 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 14397 + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 14398 + "license": "MIT" 14399 + }, 14400 + "node_modules/send/node_modules/encodeurl": { 14401 + "version": "1.0.2", 14402 + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 14403 + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 14404 + "license": "MIT", 14405 + "engines": { 14406 + "node": ">= 0.8" 14407 + } 14408 + }, 14409 + "node_modules/send/node_modules/mime": { 14410 + "version": "1.6.0", 14411 + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 14412 + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 14413 + "license": "MIT", 14414 + "bin": { 14415 + "mime": "cli.js" 14416 + }, 14417 + "engines": { 14418 + "node": ">=4" 14419 + } 14420 + }, 14421 + "node_modules/send/node_modules/ms": { 14422 + "version": "2.1.3", 14423 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 14424 + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 14425 + "license": "MIT" 14426 + }, 14427 + "node_modules/serve-static": { 14428 + "version": "1.16.2", 14429 + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", 14430 + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", 14431 + "license": "MIT", 14432 + "dependencies": { 14433 + "encodeurl": "~2.0.0", 14434 + "escape-html": "~1.0.3", 14435 + "parseurl": "~1.3.3", 14436 + "send": "0.19.0" 14437 + }, 14438 + "engines": { 14439 + "node": ">= 0.8.0" 14440 + } 14441 + }, 12967 14442 "node_modules/server-only": { 12968 14443 "version": "0.0.1", 12969 14444 "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", ··· 12999 14474 "engines": { 13000 14475 "node": ">= 0.4" 13001 14476 } 14477 + }, 14478 + "node_modules/setprototypeof": { 14479 + "version": "1.2.0", 14480 + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 14481 + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 14482 + "license": "ISC" 13002 14483 }, 13003 14484 "node_modules/shebang-command": { 13004 14485 "version": "2.0.0", ··· 13065 14546 "node": ">=8" 13066 14547 } 13067 14548 }, 14549 + "node_modules/sonic-boom": { 14550 + "version": "3.8.1", 14551 + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", 14552 + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", 14553 + "license": "MIT", 14554 + "dependencies": { 14555 + "atomic-sleep": "^1.0.0" 14556 + } 14557 + }, 13068 14558 "node_modules/source-map": { 13069 14559 "version": "0.6.1", 13070 14560 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", ··· 13108 14598 "url": "https://github.com/sponsors/wooorm" 13109 14599 } 13110 14600 }, 14601 + "node_modules/split2": { 14602 + "version": "4.2.0", 14603 + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", 14604 + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", 14605 + "license": "ISC", 14606 + "engines": { 14607 + "node": ">= 10.x" 14608 + } 14609 + }, 13111 14610 "node_modules/stacktracey": { 13112 14611 "version": "2.1.8", 13113 14612 "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", ··· 13118 14617 "get-source": "^2.0.12" 13119 14618 } 13120 14619 }, 14620 + "node_modules/statuses": { 14621 + "version": "2.0.1", 14622 + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 14623 + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 14624 + "license": "MIT", 14625 + "engines": { 14626 + "node": ">= 0.8" 14627 + } 14628 + }, 13121 14629 "node_modules/stoppable": { 13122 14630 "version": "1.1.0", 13123 14631 "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", ··· 13134 14642 "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", 13135 14643 "engines": { 13136 14644 "node": ">=10.0.0" 14645 + } 14646 + }, 14647 + "node_modules/string_decoder": { 14648 + "version": "1.3.0", 14649 + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 14650 + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 14651 + "license": "MIT", 14652 + "dependencies": { 14653 + "safe-buffer": "~5.2.0" 13137 14654 } 13138 14655 }, 13139 14656 "node_modules/string-width": { ··· 13559 15076 "node": ">=0.8" 13560 15077 } 13561 15078 }, 15079 + "node_modules/thread-stream": { 15080 + "version": "2.7.0", 15081 + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", 15082 + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", 15083 + "license": "MIT", 15084 + "dependencies": { 15085 + "real-require": "^0.2.0" 15086 + } 15087 + }, 13562 15088 "node_modules/thumbhash": { 13563 15089 "version": "0.1.1", 13564 15090 "resolved": "https://registry.npmjs.org/thumbhash/-/thumbhash-0.1.1.tgz", ··· 13575 15101 } 13576 15102 }, 13577 15103 "node_modules/tlds": { 13578 - "version": "1.255.0", 13579 - "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz", 13580 - "integrity": "sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw==", 15104 + "version": "1.256.0", 15105 + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.256.0.tgz", 15106 + "integrity": "sha512-ZmyVB9DAw+FFTmLElGYJgdZFsKLYd/I59Bg9NHkCGPwAbVZNRilFWDMAdX8UG+bHuv7kfursd5XGqo/9wi26lA==", 13581 15107 "license": "MIT", 13582 15108 "bin": { 13583 15109 "tlds": "bin.js" ··· 13595 15121 "node": ">=8.0" 13596 15122 } 13597 15123 }, 15124 + "node_modules/toidentifier": { 15125 + "version": "1.0.1", 15126 + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 15127 + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 15128 + "license": "MIT", 15129 + "engines": { 15130 + "node": ">=0.6" 15131 + } 15132 + }, 13598 15133 "node_modules/tr46": { 13599 15134 "version": "5.0.0", 13600 15135 "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", ··· 13652 15187 "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", 13653 15188 "dev": true 13654 15189 }, 15190 + "node_modules/ts-morph": { 15191 + "version": "16.0.0", 15192 + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-16.0.0.tgz", 15193 + "integrity": "sha512-jGNF0GVpFj0orFw55LTsQxVYEUOCWBAbR5Ls7fTYE5pQsbW18ssTb/6UXx/GYAEjS+DQTp8VoTw0vqYMiaaQuw==", 15194 + "dev": true, 15195 + "license": "MIT", 15196 + "dependencies": { 15197 + "@ts-morph/common": "~0.17.0", 15198 + "code-block-writer": "^11.0.3" 15199 + } 15200 + }, 13655 15201 "node_modules/tsconfig-paths": { 13656 15202 "version": "3.15.0", 13657 15203 "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", ··· 13669 15215 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", 13670 15216 "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" 13671 15217 }, 15218 + "node_modules/tsx": { 15219 + "version": "4.19.3", 15220 + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", 15221 + "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", 15222 + "dev": true, 15223 + "license": "MIT", 15224 + "dependencies": { 15225 + "esbuild": "~0.25.0", 15226 + "get-tsconfig": "^4.7.5" 15227 + }, 15228 + "bin": { 15229 + "tsx": "dist/cli.mjs" 15230 + }, 15231 + "engines": { 15232 + "node": ">=18.0.0" 15233 + }, 15234 + "optionalDependencies": { 15235 + "fsevents": "~2.3.3" 15236 + } 15237 + }, 15238 + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { 15239 + "version": "0.25.1", 15240 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", 15241 + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", 15242 + "cpu": [ 15243 + "ppc64" 15244 + ], 15245 + "dev": true, 15246 + "license": "MIT", 15247 + "optional": true, 15248 + "os": [ 15249 + "aix" 15250 + ], 15251 + "engines": { 15252 + "node": ">=18" 15253 + } 15254 + }, 15255 + "node_modules/tsx/node_modules/@esbuild/android-arm": { 15256 + "version": "0.25.1", 15257 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", 15258 + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", 15259 + "cpu": [ 15260 + "arm" 15261 + ], 15262 + "dev": true, 15263 + "license": "MIT", 15264 + "optional": true, 15265 + "os": [ 15266 + "android" 15267 + ], 15268 + "engines": { 15269 + "node": ">=18" 15270 + } 15271 + }, 15272 + "node_modules/tsx/node_modules/@esbuild/android-arm64": { 15273 + "version": "0.25.1", 15274 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", 15275 + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", 15276 + "cpu": [ 15277 + "arm64" 15278 + ], 15279 + "dev": true, 15280 + "license": "MIT", 15281 + "optional": true, 15282 + "os": [ 15283 + "android" 15284 + ], 15285 + "engines": { 15286 + "node": ">=18" 15287 + } 15288 + }, 15289 + "node_modules/tsx/node_modules/@esbuild/android-x64": { 15290 + "version": "0.25.1", 15291 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", 15292 + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", 15293 + "cpu": [ 15294 + "x64" 15295 + ], 15296 + "dev": true, 15297 + "license": "MIT", 15298 + "optional": true, 15299 + "os": [ 15300 + "android" 15301 + ], 15302 + "engines": { 15303 + "node": ">=18" 15304 + } 15305 + }, 15306 + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { 15307 + "version": "0.25.1", 15308 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", 15309 + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", 15310 + "cpu": [ 15311 + "arm64" 15312 + ], 15313 + "dev": true, 15314 + "license": "MIT", 15315 + "optional": true, 15316 + "os": [ 15317 + "darwin" 15318 + ], 15319 + "engines": { 15320 + "node": ">=18" 15321 + } 15322 + }, 15323 + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { 15324 + "version": "0.25.1", 15325 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", 15326 + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", 15327 + "cpu": [ 15328 + "x64" 15329 + ], 15330 + "dev": true, 15331 + "license": "MIT", 15332 + "optional": true, 15333 + "os": [ 15334 + "darwin" 15335 + ], 15336 + "engines": { 15337 + "node": ">=18" 15338 + } 15339 + }, 15340 + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { 15341 + "version": "0.25.1", 15342 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", 15343 + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", 15344 + "cpu": [ 15345 + "arm64" 15346 + ], 15347 + "dev": true, 15348 + "license": "MIT", 15349 + "optional": true, 15350 + "os": [ 15351 + "freebsd" 15352 + ], 15353 + "engines": { 15354 + "node": ">=18" 15355 + } 15356 + }, 15357 + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { 15358 + "version": "0.25.1", 15359 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", 15360 + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", 15361 + "cpu": [ 15362 + "x64" 15363 + ], 15364 + "dev": true, 15365 + "license": "MIT", 15366 + "optional": true, 15367 + "os": [ 15368 + "freebsd" 15369 + ], 15370 + "engines": { 15371 + "node": ">=18" 15372 + } 15373 + }, 15374 + "node_modules/tsx/node_modules/@esbuild/linux-arm": { 15375 + "version": "0.25.1", 15376 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", 15377 + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", 15378 + "cpu": [ 15379 + "arm" 15380 + ], 15381 + "dev": true, 15382 + "license": "MIT", 15383 + "optional": true, 15384 + "os": [ 15385 + "linux" 15386 + ], 15387 + "engines": { 15388 + "node": ">=18" 15389 + } 15390 + }, 15391 + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { 15392 + "version": "0.25.1", 15393 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", 15394 + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", 15395 + "cpu": [ 15396 + "arm64" 15397 + ], 15398 + "dev": true, 15399 + "license": "MIT", 15400 + "optional": true, 15401 + "os": [ 15402 + "linux" 15403 + ], 15404 + "engines": { 15405 + "node": ">=18" 15406 + } 15407 + }, 15408 + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { 15409 + "version": "0.25.1", 15410 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", 15411 + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", 15412 + "cpu": [ 15413 + "ia32" 15414 + ], 15415 + "dev": true, 15416 + "license": "MIT", 15417 + "optional": true, 15418 + "os": [ 15419 + "linux" 15420 + ], 15421 + "engines": { 15422 + "node": ">=18" 15423 + } 15424 + }, 15425 + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { 15426 + "version": "0.25.1", 15427 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", 15428 + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", 15429 + "cpu": [ 15430 + "loong64" 15431 + ], 15432 + "dev": true, 15433 + "license": "MIT", 15434 + "optional": true, 15435 + "os": [ 15436 + "linux" 15437 + ], 15438 + "engines": { 15439 + "node": ">=18" 15440 + } 15441 + }, 15442 + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { 15443 + "version": "0.25.1", 15444 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", 15445 + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", 15446 + "cpu": [ 15447 + "mips64el" 15448 + ], 15449 + "dev": true, 15450 + "license": "MIT", 15451 + "optional": true, 15452 + "os": [ 15453 + "linux" 15454 + ], 15455 + "engines": { 15456 + "node": ">=18" 15457 + } 15458 + }, 15459 + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { 15460 + "version": "0.25.1", 15461 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", 15462 + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", 15463 + "cpu": [ 15464 + "ppc64" 15465 + ], 15466 + "dev": true, 15467 + "license": "MIT", 15468 + "optional": true, 15469 + "os": [ 15470 + "linux" 15471 + ], 15472 + "engines": { 15473 + "node": ">=18" 15474 + } 15475 + }, 15476 + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { 15477 + "version": "0.25.1", 15478 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", 15479 + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", 15480 + "cpu": [ 15481 + "riscv64" 15482 + ], 15483 + "dev": true, 15484 + "license": "MIT", 15485 + "optional": true, 15486 + "os": [ 15487 + "linux" 15488 + ], 15489 + "engines": { 15490 + "node": ">=18" 15491 + } 15492 + }, 15493 + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { 15494 + "version": "0.25.1", 15495 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", 15496 + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", 15497 + "cpu": [ 15498 + "s390x" 15499 + ], 15500 + "dev": true, 15501 + "license": "MIT", 15502 + "optional": true, 15503 + "os": [ 15504 + "linux" 15505 + ], 15506 + "engines": { 15507 + "node": ">=18" 15508 + } 15509 + }, 15510 + "node_modules/tsx/node_modules/@esbuild/linux-x64": { 15511 + "version": "0.25.1", 15512 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", 15513 + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", 15514 + "cpu": [ 15515 + "x64" 15516 + ], 15517 + "dev": true, 15518 + "license": "MIT", 15519 + "optional": true, 15520 + "os": [ 15521 + "linux" 15522 + ], 15523 + "engines": { 15524 + "node": ">=18" 15525 + } 15526 + }, 15527 + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { 15528 + "version": "0.25.1", 15529 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", 15530 + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", 15531 + "cpu": [ 15532 + "x64" 15533 + ], 15534 + "dev": true, 15535 + "license": "MIT", 15536 + "optional": true, 15537 + "os": [ 15538 + "netbsd" 15539 + ], 15540 + "engines": { 15541 + "node": ">=18" 15542 + } 15543 + }, 15544 + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { 15545 + "version": "0.25.1", 15546 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", 15547 + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", 15548 + "cpu": [ 15549 + "x64" 15550 + ], 15551 + "dev": true, 15552 + "license": "MIT", 15553 + "optional": true, 15554 + "os": [ 15555 + "openbsd" 15556 + ], 15557 + "engines": { 15558 + "node": ">=18" 15559 + } 15560 + }, 15561 + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { 15562 + "version": "0.25.1", 15563 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", 15564 + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", 15565 + "cpu": [ 15566 + "x64" 15567 + ], 15568 + "dev": true, 15569 + "license": "MIT", 15570 + "optional": true, 15571 + "os": [ 15572 + "sunos" 15573 + ], 15574 + "engines": { 15575 + "node": ">=18" 15576 + } 15577 + }, 15578 + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { 15579 + "version": "0.25.1", 15580 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", 15581 + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", 15582 + "cpu": [ 15583 + "arm64" 15584 + ], 15585 + "dev": true, 15586 + "license": "MIT", 15587 + "optional": true, 15588 + "os": [ 15589 + "win32" 15590 + ], 15591 + "engines": { 15592 + "node": ">=18" 15593 + } 15594 + }, 15595 + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { 15596 + "version": "0.25.1", 15597 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", 15598 + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", 15599 + "cpu": [ 15600 + "ia32" 15601 + ], 15602 + "dev": true, 15603 + "license": "MIT", 15604 + "optional": true, 15605 + "os": [ 15606 + "win32" 15607 + ], 15608 + "engines": { 15609 + "node": ">=18" 15610 + } 15611 + }, 15612 + "node_modules/tsx/node_modules/@esbuild/win32-x64": { 15613 + "version": "0.25.1", 15614 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", 15615 + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", 15616 + "cpu": [ 15617 + "x64" 15618 + ], 15619 + "dev": true, 15620 + "license": "MIT", 15621 + "optional": true, 15622 + "os": [ 15623 + "win32" 15624 + ], 15625 + "engines": { 15626 + "node": ">=18" 15627 + } 15628 + }, 15629 + "node_modules/tsx/node_modules/esbuild": { 15630 + "version": "0.25.1", 15631 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", 15632 + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", 15633 + "dev": true, 15634 + "hasInstallScript": true, 15635 + "license": "MIT", 15636 + "bin": { 15637 + "esbuild": "bin/esbuild" 15638 + }, 15639 + "engines": { 15640 + "node": ">=18" 15641 + }, 15642 + "optionalDependencies": { 15643 + "@esbuild/aix-ppc64": "0.25.1", 15644 + "@esbuild/android-arm": "0.25.1", 15645 + "@esbuild/android-arm64": "0.25.1", 15646 + "@esbuild/android-x64": "0.25.1", 15647 + "@esbuild/darwin-arm64": "0.25.1", 15648 + "@esbuild/darwin-x64": "0.25.1", 15649 + "@esbuild/freebsd-arm64": "0.25.1", 15650 + "@esbuild/freebsd-x64": "0.25.1", 15651 + "@esbuild/linux-arm": "0.25.1", 15652 + "@esbuild/linux-arm64": "0.25.1", 15653 + "@esbuild/linux-ia32": "0.25.1", 15654 + "@esbuild/linux-loong64": "0.25.1", 15655 + "@esbuild/linux-mips64el": "0.25.1", 15656 + "@esbuild/linux-ppc64": "0.25.1", 15657 + "@esbuild/linux-riscv64": "0.25.1", 15658 + "@esbuild/linux-s390x": "0.25.1", 15659 + "@esbuild/linux-x64": "0.25.1", 15660 + "@esbuild/netbsd-arm64": "0.25.1", 15661 + "@esbuild/netbsd-x64": "0.25.1", 15662 + "@esbuild/openbsd-arm64": "0.25.1", 15663 + "@esbuild/openbsd-x64": "0.25.1", 15664 + "@esbuild/sunos-x64": "0.25.1", 15665 + "@esbuild/win32-arm64": "0.25.1", 15666 + "@esbuild/win32-ia32": "0.25.1", 15667 + "@esbuild/win32-x64": "0.25.1" 15668 + } 15669 + }, 13672 15670 "node_modules/twilio": { 13673 15671 "version": "5.3.7", 13674 15672 "resolved": "https://registry.npmjs.org/twilio/-/twilio-5.3.7.tgz", ··· 13740 15738 }, 13741 15739 "funding": { 13742 15740 "url": "https://github.com/sponsors/sindresorhus" 15741 + } 15742 + }, 15743 + "node_modules/type-is": { 15744 + "version": "1.6.18", 15745 + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 15746 + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 15747 + "license": "MIT", 15748 + "dependencies": { 15749 + "media-typer": "0.3.0", 15750 + "mime-types": "~2.1.24" 15751 + }, 15752 + "engines": { 15753 + "node": ">= 0.6" 13743 15754 } 13744 15755 }, 13745 15756 "node_modules/typed-array-buffer": { ··· 13832 15843 "version": "2.1.0", 13833 15844 "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", 13834 15845 "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", 15846 + "license": "MIT", 13835 15847 "peer": true 13836 15848 }, 13837 15849 "node_modules/uint8arrays": { ··· 13843 15855 "multiformats": "^9.4.2" 13844 15856 } 13845 15857 }, 15858 + "node_modules/uint8arrays/node_modules/multiformats": { 15859 + "version": "9.9.0", 15860 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 15861 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 15862 + "license": "(Apache-2.0 AND MIT)" 15863 + }, 13846 15864 "node_modules/unbox-primitive": { 13847 15865 "version": "1.0.2", 13848 15866 "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", ··· 13856 15874 }, 13857 15875 "funding": { 13858 15876 "url": "https://github.com/sponsors/ljharb" 15877 + } 15878 + }, 15879 + "node_modules/undici": { 15880 + "version": "6.21.1", 15881 + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", 15882 + "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", 15883 + "license": "MIT", 15884 + "engines": { 15885 + "node": ">=18.17" 13859 15886 } 13860 15887 }, 13861 15888 "node_modules/undici-types": { ··· 13969 15996 "url": "https://opencollective.com/unified" 13970 15997 } 13971 15998 }, 15999 + "node_modules/unpipe": { 16000 + "version": "1.0.0", 16001 + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 16002 + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 16003 + "license": "MIT", 16004 + "engines": { 16005 + "node": ">= 0.8" 16006 + } 16007 + }, 13972 16008 "node_modules/update-browserslist-db": { 13973 16009 "version": "1.0.16", 13974 16010 "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", ··· 14054 16090 "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 14055 16091 "dev": true 14056 16092 }, 16093 + "node_modules/utils-merge": { 16094 + "version": "1.0.1", 16095 + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 16096 + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 16097 + "license": "MIT", 16098 + "engines": { 16099 + "node": ">= 0.4.0" 16100 + } 16101 + }, 14057 16102 "node_modules/uuid": { 14058 16103 "version": "10.0.0", 14059 16104 "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", ··· 14064 16109 ], 14065 16110 "bin": { 14066 16111 "uuid": "dist/bin/uuid" 16112 + } 16113 + }, 16114 + "node_modules/varint": { 16115 + "version": "6.0.0", 16116 + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", 16117 + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", 16118 + "license": "MIT" 16119 + }, 16120 + "node_modules/vary": { 16121 + "version": "1.1.2", 16122 + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 16123 + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 16124 + "license": "MIT", 16125 + "engines": { 16126 + "node": ">= 0.8" 14067 16127 } 14068 16128 }, 14069 16129 "node_modules/vfile": { ··· 14844 16904 "engines": { 14845 16905 "node": ">= 14" 14846 16906 } 16907 + }, 16908 + "node_modules/yesno": { 16909 + "version": "0.4.0", 16910 + "resolved": "https://registry.npmjs.org/yesno/-/yesno-0.4.0.tgz", 16911 + "integrity": "sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==", 16912 + "dev": true, 16913 + "license": "BSD" 14847 16914 }, 14848 16915 "node_modules/yjs": { 14849 16916 "version": "13.6.15",
+13 -1
package.json
··· 5 5 "main": "index.js", 6 6 "scripts": { 7 7 "dev": "next dev", 8 - "wrangler-dev": "wrangler dev" 8 + "lexgen": "tsx ./lexicons/build.ts && lex gen-api ./lexicons/src ./lexicons/out/* ./lexicons/com/atproto/*/* --yes", 9 + "wrangler-dev": "wrangler dev", 10 + "start-appview": "tsx --env-file='./.env.local' --watch appview/index.ts" 9 11 }, 10 12 "keywords": [], 11 13 "author": "", 12 14 "license": "ISC", 13 15 "dependencies": { 14 16 "@atproto/api": "^0.14.2", 17 + "@atproto/common": "^0.4.8", 18 + "@atproto/identity": "^0.4.6", 19 + "@atproto/sync": "^0.1.17", 20 + "@atproto/syntax": "^0.3.3", 21 + "@atproto/xrpc": "^0.6.9", 22 + "@atproto/oauth-client-node": "^0.2.8", 15 23 "@mdx-js/loader": "^3.1.0", 16 24 "@mdx-js/react": "^3.1.0", 17 25 "@next/mdx": "^15.0.3", ··· 35 43 "drizzle-orm": "^0.30.10", 36 44 "fractional-indexing": "^3.2.0", 37 45 "linkifyjs": "^4.2.0", 46 + "multiformats": "^13.3.2", 38 47 "next": "^14.2.4", 39 48 "postgres": "^3.4.4", 40 49 "prosemirror-commands": "^1.5.2", ··· 68 77 "zustand": "^4.5.2" 69 78 }, 70 79 "devDependencies": { 80 + "@atproto/lex-cli": "^0.6.1", 81 + "@atproto/lexicon": "^0.4.7", 71 82 "@cloudflare/workers-types": "^4.20240512.0", 72 83 "@types/react": "18.3.2", 73 84 "@types/react-dom": "^18.3.0", ··· 80 91 "prettier": "3.2.5", 81 92 "supabase": "^1.187.3", 82 93 "tailwindcss": "^3.4.3", 94 + "tsx": "^4.19.3", 83 95 "typescript": "^5.5.3", 84 96 "wrangler": "^3.56.0" 85 97 },
+74
src/atproto-oauth.ts
··· 1 + import { 2 + NodeOAuthClient, 3 + NodeSavedSession, 4 + NodeSavedState, 5 + Session, 6 + } from "@atproto/oauth-client-node"; 7 + import { JoseKey } from "@atproto/jwk-jose"; 8 + import { oauth_metadata } from "app/api/oauth/[route]/oauth-metadata"; 9 + import { supabaseServerClient } from "supabase/serverClient"; 10 + 11 + export async function createOauthClient() { 12 + let keyset = 13 + process.env.NODE_ENV === "production" 14 + ? await Promise.all([ 15 + JoseKey.fromImportable(process.env.JOSE_PRIVATE_KEY_1!), 16 + ]) 17 + : undefined; 18 + return new NodeOAuthClient({ 19 + // This object will be used to build the payload of the /client-metadata.json 20 + // endpoint metadata, exposing the client metadata to the OAuth server. 21 + clientMetadata: oauth_metadata, 22 + 23 + // Used to authenticate the client to the token endpoint. Will be used to 24 + // build the jwks object to be exposed on the "jwks_uri" endpoint. 25 + keyset, 26 + 27 + // Interface to store authorization state data (during authorization flows) 28 + stateStore, 29 + // Interface to store authenticated session data 30 + sessionStore, 31 + }); 32 + } 33 + 34 + let stateStore = { 35 + async set(key: string, state: NodeSavedState): Promise<void> { 36 + await supabaseServerClient.from("oauth_state_store").upsert({ key, state }); 37 + }, 38 + async get(key: string): Promise<NodeSavedState | undefined> { 39 + let { data } = await supabaseServerClient 40 + .from("oauth_state_store") 41 + .select("state") 42 + .eq("key", key) 43 + .single(); 44 + return (data?.state as NodeSavedState) || undefined; 45 + }, 46 + async del(key: string): Promise<void> { 47 + await supabaseServerClient 48 + .from("oauth_state_store") 49 + .delete() 50 + .eq("key", key); 51 + }, 52 + }; 53 + 54 + let sessionStore = { 55 + async set(key: string, session: NodeSavedSession): Promise<void> { 56 + await supabaseServerClient 57 + .from("oauth_session_store") 58 + .upsert({ key, session }); 59 + }, 60 + async get(key: string): Promise<NodeSavedSession | undefined> { 61 + let { data } = await supabaseServerClient 62 + .from("oauth_session_store") 63 + .select("session") 64 + .eq("key", key) 65 + .single(); 66 + return (data?.session as NodeSavedSession) || undefined; 67 + }, 68 + async del(key: string): Promise<void> { 69 + await supabaseServerClient 70 + .from("oauth_session_store") 71 + .delete() 72 + .eq("key", key); 73 + }, 74 + };
+5
src/utils/generateJoseKey.js
··· 1 + import { JoseKey } from "@atproto/jwk-jose"; 2 + (async () => { 3 + let key = await JoseKey.generate(); 4 + console.log(JSON.stringify(key.privateJwk)); 5 + })();
+181 -3
supabase/database.types.ts
··· 112 112 }, 113 113 ] 114 114 } 115 + documents: { 116 + Row: { 117 + data: Json 118 + indexed_at: string 119 + uri: string 120 + } 121 + Insert: { 122 + data: Json 123 + indexed_at?: string 124 + uri: string 125 + } 126 + Update: { 127 + data?: Json 128 + indexed_at?: string 129 + uri?: string 130 + } 131 + Relationships: [] 132 + } 133 + documents_in_publications: { 134 + Row: { 135 + document: string 136 + indexed_at: string 137 + publication: string 138 + } 139 + Insert: { 140 + document: string 141 + indexed_at?: string 142 + publication: string 143 + } 144 + Update: { 145 + document?: string 146 + indexed_at?: string 147 + publication?: string 148 + } 149 + Relationships: [ 150 + { 151 + foreignKeyName: "documents_in_publications_document_fkey" 152 + columns: ["document"] 153 + isOneToOne: false 154 + referencedRelation: "documents" 155 + referencedColumns: ["uri"] 156 + }, 157 + { 158 + foreignKeyName: "documents_in_publications_publication_fkey" 159 + columns: ["publication"] 160 + isOneToOne: false 161 + referencedRelation: "publications" 162 + referencedColumns: ["uri"] 163 + }, 164 + ] 165 + } 115 166 email_auth_tokens: { 116 167 Row: { 117 168 confirmation_code: string 118 169 confirmed: boolean 119 170 created_at: string 120 - email: string 171 + email: string | null 121 172 id: string 122 173 identity: string | null 123 174 } ··· 125 176 confirmation_code: string 126 177 confirmed?: boolean 127 178 created_at?: string 128 - email: string 179 + email?: string | null 129 180 id?: string 130 181 identity?: string | null 131 182 } ··· 133 184 confirmation_code?: string 134 185 confirmed?: boolean 135 186 created_at?: string 136 - email?: string 187 + email?: string | null 137 188 id?: string 138 189 identity?: string | null 139 190 } ··· 273 324 } 274 325 identities: { 275 326 Row: { 327 + atp_did: string | null 276 328 created_at: string 277 329 email: string | null 278 330 home_page: string 279 331 id: string 280 332 } 281 333 Insert: { 334 + atp_did?: string | null 282 335 created_at?: string 283 336 email?: string | null 284 337 home_page: string 285 338 id?: string 286 339 } 287 340 Update: { 341 + atp_did?: string | null 288 342 created_at?: string 289 343 email?: string | null 290 344 home_page?: string ··· 300 354 }, 301 355 ] 302 356 } 357 + leaflets_in_publications: { 358 + Row: { 359 + doc: string | null 360 + leaflet: string 361 + publication: string 362 + } 363 + Insert: { 364 + doc?: string | null 365 + leaflet: string 366 + publication: string 367 + } 368 + Update: { 369 + doc?: string | null 370 + leaflet?: string 371 + publication?: string 372 + } 373 + Relationships: [ 374 + { 375 + foreignKeyName: "leaflets_in_publications_doc_fkey" 376 + columns: ["doc"] 377 + isOneToOne: false 378 + referencedRelation: "documents" 379 + referencedColumns: ["uri"] 380 + }, 381 + { 382 + foreignKeyName: "leaflets_in_publications_leaflet_fkey" 383 + columns: ["leaflet"] 384 + isOneToOne: false 385 + referencedRelation: "permission_tokens" 386 + referencedColumns: ["id"] 387 + }, 388 + { 389 + foreignKeyName: "leaflets_in_publications_publication_fkey" 390 + columns: ["publication"] 391 + isOneToOne: false 392 + referencedRelation: "publications" 393 + referencedColumns: ["uri"] 394 + }, 395 + ] 396 + } 397 + oauth_session_store: { 398 + Row: { 399 + key: string 400 + session: Json 401 + } 402 + Insert: { 403 + key: string 404 + session: Json 405 + } 406 + Update: { 407 + key?: string 408 + session?: Json 409 + } 410 + Relationships: [] 411 + } 412 + oauth_state_store: { 413 + Row: { 414 + key: string 415 + state: Json 416 + } 417 + Insert: { 418 + key: string 419 + state: Json 420 + } 421 + Update: { 422 + key?: string 423 + state?: Json 424 + } 425 + Relationships: [] 426 + } 303 427 permission_token_on_homepage: { 304 428 Row: { 305 429 created_at: string ··· 511 635 }, 512 636 ] 513 637 } 638 + publications: { 639 + Row: { 640 + identity_did: string 641 + indexed_at: string 642 + name: string 643 + uri: string 644 + } 645 + Insert: { 646 + identity_did: string 647 + indexed_at?: string 648 + name: string 649 + uri: string 650 + } 651 + Update: { 652 + identity_did?: string 653 + indexed_at?: string 654 + name?: string 655 + uri?: string 656 + } 657 + Relationships: [] 658 + } 514 659 replicache_clients: { 515 660 Row: { 516 661 client_group: string ··· 528 673 last_mutation?: number 529 674 } 530 675 Relationships: [] 676 + } 677 + subscribers_to_publications: { 678 + Row: { 679 + created_at: string 680 + identity: string 681 + publication: string 682 + } 683 + Insert: { 684 + created_at?: string 685 + identity: string 686 + publication: string 687 + } 688 + Update: { 689 + created_at?: string 690 + identity?: string 691 + publication?: string 692 + } 693 + Relationships: [ 694 + { 695 + foreignKeyName: "subscribers_to_publications_identity_fkey" 696 + columns: ["identity"] 697 + isOneToOne: false 698 + referencedRelation: "identities" 699 + referencedColumns: ["email"] 700 + }, 701 + { 702 + foreignKeyName: "subscribers_to_publications_publication_fkey" 703 + columns: ["publication"] 704 + isOneToOne: false 705 + referencedRelation: "publications" 706 + referencedColumns: ["uri"] 707 + }, 708 + ] 531 709 } 532 710 } 533 711 Views: {
+153
supabase/migrations/20250320201458_add_publication_and_bsky_tables.sql
··· 1 + create table "public"."documents" ( 2 + "uri" text not null, 3 + "data" jsonb not null, 4 + "indexed_at" timestamp with time zone not null default now() 5 + ); 6 + alter table "public"."documents" enable row level security; 7 + create table "public"."documents_in_publications" ( 8 + "publication" text not null, 9 + "document" text not null, 10 + "indexed_at" timestamp with time zone not null default now() 11 + ); 12 + alter table "public"."documents_in_publications" enable row level security; 13 + create table "public"."oauth_session_store" ( 14 + "key" text not null, 15 + "session" jsonb not null 16 + ); 17 + alter table "public"."oauth_session_store" enable row level security; 18 + create table "public"."oauth_state_store" ( 19 + "key" text not null, 20 + "state" jsonb not null 21 + ); 22 + alter table "public"."oauth_state_store" enable row level security; 23 + create table "public"."publications" ( 24 + "uri" text not null, 25 + "indexed_at" timestamp with time zone not null default now(), 26 + "name" text not null, 27 + "identity_did" text not null 28 + ); 29 + alter table "public"."publications" enable row level security; 30 + alter table "public"."email_auth_tokens" alter column "email" drop not null; 31 + alter table "public"."identities" add column "atp_did" text; 32 + CREATE UNIQUE INDEX documents_in_publications_pkey ON public.documents_in_publications USING btree (publication, document); 33 + CREATE UNIQUE INDEX documents_pkey ON public.documents USING btree (uri); 34 + CREATE UNIQUE INDEX identities_atp_did_key ON public.identities USING btree (atp_did); 35 + CREATE UNIQUE INDEX oauth_session_store_pkey ON public.oauth_session_store USING btree (key); 36 + CREATE UNIQUE INDEX oauth_state_store_pkey ON public.oauth_state_store USING btree (key); 37 + CREATE UNIQUE INDEX publications_pkey ON public.publications USING btree (uri); 38 + alter table "public"."documents" add constraint "documents_pkey" PRIMARY KEY using index "documents_pkey"; 39 + alter table "public"."documents_in_publications" add constraint "documents_in_publications_pkey" PRIMARY KEY using index "documents_in_publications_pkey"; 40 + alter table "public"."oauth_session_store" add constraint "oauth_session_store_pkey" PRIMARY KEY using index "oauth_session_store_pkey"; 41 + alter table "public"."oauth_state_store" add constraint "oauth_state_store_pkey" PRIMARY KEY using index "oauth_state_store_pkey"; 42 + alter table "public"."publications" add constraint "publications_pkey" PRIMARY KEY using index "publications_pkey"; 43 + alter table "public"."documents_in_publications" add constraint "documents_in_publications_document_fkey" FOREIGN KEY (document) REFERENCES documents(uri) ON DELETE CASCADE not valid; 44 + alter table "public"."documents_in_publications" validate constraint "documents_in_publications_document_fkey"; 45 + alter table "public"."documents_in_publications" add constraint "documents_in_publications_publication_fkey" FOREIGN KEY (publication) REFERENCES publications(uri) ON DELETE CASCADE not valid; 46 + alter table "public"."documents_in_publications" validate constraint "documents_in_publications_publication_fkey"; 47 + alter table "public"."identities" add constraint "identities_atp_did_key" UNIQUE using index "identities_atp_did_key"; 48 + grant delete on table "public"."documents" to "anon"; 49 + grant insert on table "public"."documents" to "anon"; 50 + grant references on table "public"."documents" to "anon"; 51 + grant select on table "public"."documents" to "anon"; 52 + grant trigger on table "public"."documents" to "anon"; 53 + grant truncate on table "public"."documents" to "anon"; 54 + grant update on table "public"."documents" to "anon"; 55 + grant delete on table "public"."documents" to "authenticated"; 56 + grant insert on table "public"."documents" to "authenticated"; 57 + grant references on table "public"."documents" to "authenticated"; 58 + grant select on table "public"."documents" to "authenticated"; 59 + grant trigger on table "public"."documents" to "authenticated"; 60 + grant truncate on table "public"."documents" to "authenticated"; 61 + grant update on table "public"."documents" to "authenticated"; 62 + grant delete on table "public"."documents" to "service_role"; 63 + grant insert on table "public"."documents" to "service_role"; 64 + grant references on table "public"."documents" to "service_role"; 65 + grant select on table "public"."documents" to "service_role"; 66 + grant trigger on table "public"."documents" to "service_role"; 67 + grant truncate on table "public"."documents" to "service_role"; 68 + grant update on table "public"."documents" to "service_role"; 69 + grant delete on table "public"."documents_in_publications" to "anon"; 70 + grant insert on table "public"."documents_in_publications" to "anon"; 71 + grant references on table "public"."documents_in_publications" to "anon"; 72 + grant select on table "public"."documents_in_publications" to "anon"; 73 + grant trigger on table "public"."documents_in_publications" to "anon"; 74 + grant truncate on table "public"."documents_in_publications" to "anon"; 75 + grant update on table "public"."documents_in_publications" to "anon"; 76 + grant delete on table "public"."documents_in_publications" to "authenticated"; 77 + grant insert on table "public"."documents_in_publications" to "authenticated"; 78 + grant references on table "public"."documents_in_publications" to "authenticated"; 79 + grant select on table "public"."documents_in_publications" to "authenticated"; 80 + grant trigger on table "public"."documents_in_publications" to "authenticated"; 81 + grant truncate on table "public"."documents_in_publications" to "authenticated"; 82 + grant update on table "public"."documents_in_publications" to "authenticated"; 83 + grant delete on table "public"."documents_in_publications" to "service_role"; 84 + grant insert on table "public"."documents_in_publications" to "service_role"; 85 + grant references on table "public"."documents_in_publications" to "service_role"; 86 + grant select on table "public"."documents_in_publications" to "service_role"; 87 + grant trigger on table "public"."documents_in_publications" to "service_role"; 88 + grant truncate on table "public"."documents_in_publications" to "service_role"; 89 + grant update on table "public"."documents_in_publications" to "service_role"; 90 + grant delete on table "public"."oauth_session_store" to "anon"; 91 + grant insert on table "public"."oauth_session_store" to "anon"; 92 + grant references on table "public"."oauth_session_store" to "anon"; 93 + grant select on table "public"."oauth_session_store" to "anon"; 94 + grant trigger on table "public"."oauth_session_store" to "anon"; 95 + grant truncate on table "public"."oauth_session_store" to "anon"; 96 + grant update on table "public"."oauth_session_store" to "anon"; 97 + grant delete on table "public"."oauth_session_store" to "authenticated"; 98 + grant insert on table "public"."oauth_session_store" to "authenticated"; 99 + grant references on table "public"."oauth_session_store" to "authenticated"; 100 + grant select on table "public"."oauth_session_store" to "authenticated"; 101 + grant trigger on table "public"."oauth_session_store" to "authenticated"; 102 + grant truncate on table "public"."oauth_session_store" to "authenticated"; 103 + grant update on table "public"."oauth_session_store" to "authenticated"; 104 + grant delete on table "public"."oauth_session_store" to "service_role"; 105 + grant insert on table "public"."oauth_session_store" to "service_role"; 106 + grant references on table "public"."oauth_session_store" to "service_role"; 107 + grant select on table "public"."oauth_session_store" to "service_role"; 108 + grant trigger on table "public"."oauth_session_store" to "service_role"; 109 + grant truncate on table "public"."oauth_session_store" to "service_role"; 110 + grant update on table "public"."oauth_session_store" to "service_role"; 111 + grant delete on table "public"."oauth_state_store" to "anon"; 112 + grant insert on table "public"."oauth_state_store" to "anon"; 113 + grant references on table "public"."oauth_state_store" to "anon"; 114 + grant select on table "public"."oauth_state_store" to "anon"; 115 + grant trigger on table "public"."oauth_state_store" to "anon"; 116 + grant truncate on table "public"."oauth_state_store" to "anon"; 117 + grant update on table "public"."oauth_state_store" to "anon"; 118 + grant delete on table "public"."oauth_state_store" to "authenticated"; 119 + grant insert on table "public"."oauth_state_store" to "authenticated"; 120 + grant references on table "public"."oauth_state_store" to "authenticated"; 121 + grant select on table "public"."oauth_state_store" to "authenticated"; 122 + grant trigger on table "public"."oauth_state_store" to "authenticated"; 123 + grant truncate on table "public"."oauth_state_store" to "authenticated"; 124 + grant update on table "public"."oauth_state_store" to "authenticated"; 125 + grant delete on table "public"."oauth_state_store" to "service_role"; 126 + grant insert on table "public"."oauth_state_store" to "service_role"; 127 + grant references on table "public"."oauth_state_store" to "service_role"; 128 + grant select on table "public"."oauth_state_store" to "service_role"; 129 + grant trigger on table "public"."oauth_state_store" to "service_role"; 130 + grant truncate on table "public"."oauth_state_store" to "service_role"; 131 + grant update on table "public"."oauth_state_store" to "service_role"; 132 + grant delete on table "public"."publications" to "anon"; 133 + grant insert on table "public"."publications" to "anon"; 134 + grant references on table "public"."publications" to "anon"; 135 + grant select on table "public"."publications" to "anon"; 136 + grant trigger on table "public"."publications" to "anon"; 137 + grant truncate on table "public"."publications" to "anon"; 138 + grant update on table "public"."publications" to "anon"; 139 + grant delete on table "public"."publications" to "authenticated"; 140 + grant insert on table "public"."publications" to "authenticated"; 141 + grant references on table "public"."publications" to "authenticated"; 142 + grant select on table "public"."publications" to "authenticated"; 143 + grant trigger on table "public"."publications" to "authenticated"; 144 + grant truncate on table "public"."publications" to "authenticated"; 145 + grant update on table "public"."publications" to "authenticated"; 146 + grant delete on table "public"."publications" to "service_role"; 147 + grant insert on table "public"."publications" to "service_role"; 148 + grant references on table "public"."publications" to "service_role"; 149 + grant select on table "public"."publications" to "service_role"; 150 + grant trigger on table "public"."publications" to "service_role"; 151 + grant truncate on table "public"."publications" to "service_role"; 152 + grant update on table "public"."publications" to "service_role"; 153 + create schema if not exists "publications";
+35
supabase/migrations/20250321200353_add_drafts_in_publications_table.sql
··· 1 + create table "public"."leaflets_in_publications" ( 2 + "publication" text not null, 3 + "doc" text default ''::text, 4 + "leaflet" uuid not null 5 + ); 6 + alter table "public"."leaflets_in_publications" enable row level security; 7 + CREATE UNIQUE INDEX leaflets_in_publications_pkey ON public.leaflets_in_publications USING btree (publication, leaflet); 8 + alter table "public"."leaflets_in_publications" add constraint "leaflets_in_publications_pkey" PRIMARY KEY using index "leaflets_in_publications_pkey"; 9 + alter table "public"."leaflets_in_publications" add constraint "leaflets_in_publications_doc_fkey" FOREIGN KEY (doc) REFERENCES documents(uri) not valid; 10 + alter table "public"."leaflets_in_publications" validate constraint "leaflets_in_publications_doc_fkey"; 11 + alter table "public"."leaflets_in_publications" add constraint "leaflets_in_publications_leaflet_fkey" FOREIGN KEY (leaflet) REFERENCES permission_tokens(id) not valid; 12 + alter table "public"."leaflets_in_publications" validate constraint "leaflets_in_publications_leaflet_fkey"; 13 + alter table "public"."leaflets_in_publications" add constraint "leaflets_in_publications_publication_fkey" FOREIGN KEY (publication) REFERENCES publications(uri) not valid; 14 + alter table "public"."leaflets_in_publications" validate constraint "leaflets_in_publications_publication_fkey"; 15 + grant delete on table "public"."leaflets_in_publications" to "anon"; 16 + grant insert on table "public"."leaflets_in_publications" to "anon"; 17 + grant references on table "public"."leaflets_in_publications" to "anon"; 18 + grant select on table "public"."leaflets_in_publications" to "anon"; 19 + grant trigger on table "public"."leaflets_in_publications" to "anon"; 20 + grant truncate on table "public"."leaflets_in_publications" to "anon"; 21 + grant update on table "public"."leaflets_in_publications" to "anon"; 22 + grant delete on table "public"."leaflets_in_publications" to "authenticated"; 23 + grant insert on table "public"."leaflets_in_publications" to "authenticated"; 24 + grant references on table "public"."leaflets_in_publications" to "authenticated"; 25 + grant select on table "public"."leaflets_in_publications" to "authenticated"; 26 + grant trigger on table "public"."leaflets_in_publications" to "authenticated"; 27 + grant truncate on table "public"."leaflets_in_publications" to "authenticated"; 28 + grant update on table "public"."leaflets_in_publications" to "authenticated"; 29 + grant delete on table "public"."leaflets_in_publications" to "service_role"; 30 + grant insert on table "public"."leaflets_in_publications" to "service_role"; 31 + grant references on table "public"."leaflets_in_publications" to "service_role"; 32 + grant select on table "public"."leaflets_in_publications" to "service_role"; 33 + grant trigger on table "public"."leaflets_in_publications" to "service_role"; 34 + grant truncate on table "public"."leaflets_in_publications" to "service_role"; 35 + grant update on table "public"."leaflets_in_publications" to "service_role";
+33
supabase/migrations/20250321233105_add_subscribers_to_publications_table.sql
··· 1 + create table "public"."subscribers_to_publications" ( 2 + "identity" text not null, 3 + "publication" text not null, 4 + "created_at" timestamp with time zone not null default now() 5 + ); 6 + alter table "public"."subscribers_to_publications" enable row level security; 7 + CREATE UNIQUE INDEX subscribers_to_publications_pkey ON public.subscribers_to_publications USING btree (identity, publication); 8 + alter table "public"."subscribers_to_publications" add constraint "subscribers_to_publications_pkey" PRIMARY KEY using index "subscribers_to_publications_pkey"; 9 + alter table "public"."subscribers_to_publications" add constraint "subscribers_to_publications_identity_fkey" FOREIGN KEY (identity) REFERENCES identities(email) ON UPDATE CASCADE not valid; 10 + alter table "public"."subscribers_to_publications" validate constraint "subscribers_to_publications_identity_fkey"; 11 + alter table "public"."subscribers_to_publications" add constraint "subscribers_to_publications_publication_fkey" FOREIGN KEY (publication) REFERENCES publications(uri) not valid; 12 + alter table "public"."subscribers_to_publications" validate constraint "subscribers_to_publications_publication_fkey"; 13 + grant delete on table "public"."subscribers_to_publications" to "anon"; 14 + grant insert on table "public"."subscribers_to_publications" to "anon"; 15 + grant references on table "public"."subscribers_to_publications" to "anon"; 16 + grant select on table "public"."subscribers_to_publications" to "anon"; 17 + grant trigger on table "public"."subscribers_to_publications" to "anon"; 18 + grant truncate on table "public"."subscribers_to_publications" to "anon"; 19 + grant update on table "public"."subscribers_to_publications" to "anon"; 20 + grant delete on table "public"."subscribers_to_publications" to "authenticated"; 21 + grant insert on table "public"."subscribers_to_publications" to "authenticated"; 22 + grant references on table "public"."subscribers_to_publications" to "authenticated"; 23 + grant select on table "public"."subscribers_to_publications" to "authenticated"; 24 + grant trigger on table "public"."subscribers_to_publications" to "authenticated"; 25 + grant truncate on table "public"."subscribers_to_publications" to "authenticated"; 26 + grant update on table "public"."subscribers_to_publications" to "authenticated"; 27 + grant delete on table "public"."subscribers_to_publications" to "service_role"; 28 + grant insert on table "public"."subscribers_to_publications" to "service_role"; 29 + grant references on table "public"."subscribers_to_publications" to "service_role"; 30 + grant select on table "public"."subscribers_to_publications" to "service_role"; 31 + grant trigger on table "public"."subscribers_to_publications" to "service_role"; 32 + grant truncate on table "public"."subscribers_to_publications" to "service_role"; 33 + grant update on table "public"."subscribers_to_publications" to "service_role";
+6
supabase/serverClient.ts
··· 1 + import { createClient } from "@supabase/supabase-js"; 2 + import { Database } from "supabase/database.types"; 3 + export const supabaseServerClient = createClient<Database>( 4 + process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, 5 + process.env.SUPABASE_SERVICE_ROLE_KEY as string, 6 + );
+1
tailwind.config.js
··· 66 66 67 67 fontFamily: { 68 68 sans: ["var(--font-quattro)"], 69 + serif: ["Garamond"], 69 70 }, 70 71 }, 71 72 },
+1
tsconfig.json
··· 25 25 "include": [ 26 26 "next-env.d.ts", 27 27 ".next/types/**/*.ts", 28 + "**/*.js", 28 29 "**/*.ts", 29 30 "**/*.tsx", 30 31 "**/*.mdx"