···1+import "@tylex/emitter";
2+3+namespace com.atproto.admin.disableInviteCodes {
4+ @doc("Disable some set of codes and/or all codes associated with a set of users.")
5+ @procedure
6+ op main(input: {
7+ codes?: string[];
8+ accounts?: string[];
9+ }): void;
10+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.admin.sendEmail {
4+ @doc("Send email to a user's account email address.")
5+ @procedure
6+ op main(input: {
7+ @required recipientDid: did;
8+ @required content: string;
9+ subject?: string;
10+ @required senderDid: did;
11+12+ @doc("Additional comment by the sender that won't be used in the email itself but helpful to provide more context for moderators/reviewers")
13+ comment?: string;
14+ }): {
15+ @required sent: boolean;
16+ };
17+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.admin.updateAccountPassword {
4+ @doc("Update the password for a user account as an administrator.")
5+ @procedure
6+ op main(input: {
7+ @required did: did;
8+ @required password: string;
9+ }): void;
10+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.defs {
4+ model IdentityInfo {
5+ @required did: did;
6+7+ @doc("The validated handle of the account; or 'handle.invalid' if the handle did not bi-directionally match the DID document.")
8+ @required
9+ handle: handle;
10+11+ @doc("The complete DID document for the identity.")
12+ @required
13+ didDoc: unknown;
14+ }
15+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.getRecommendedDidCredentials {
4+ @doc("Describe the credentials that should be included in the DID doc of an account that is migrating to this service.")
5+ @query
6+ op main(): {
7+ @doc("Recommended rotation keys for PLC dids. Should be undefined (or ignored) for did:webs.")
8+ rotationKeys?: string[];
9+10+ alsoKnownAs?: string[];
11+ verificationMethods?: unknown;
12+ services?: unknown;
13+ };
14+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.refreshIdentity {
4+ @doc("The resolution process confirmed that the handle does not resolve to any DID.")
5+ model HandleNotFound {}
6+7+ @doc("The DID resolution process confirmed that there is no current DID.")
8+ model DidNotFound {}
9+10+ @doc("The DID previously existed, but has been deactivated.")
11+ model DidDeactivated {}
12+13+ @doc("Request that the server re-resolve an identity (DID and handle). The server may ignore this request, or require authentication, depending on the role, implementation, and policy of the server.")
14+ @procedure
15+ @errors(HandleNotFound, DidNotFound, DidDeactivated)
16+ op main(input: {
17+ @required identifier: atIdentifier;
18+ }): com.atproto.identity.defs.IdentityInfo;
19+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.requestPlcOperationSignature {
4+ @doc("Request an email with a code to in order to request a signed PLC operation. Requires Auth.")
5+ @procedure
6+ op main(): void;
7+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.resolveDid {
4+ @doc("Resolves DID to DID document. Does not bi-directionally verify handle.")
5+ @query
6+ @errors(DidNotFound, DidDeactivated)
7+ op main(
8+ @doc("DID to resolve.")
9+ @required
10+ did: did
11+ ): {
12+ @doc("The complete DID document for the identity.")
13+ @required
14+ didDoc: unknown;
15+ };
16+17+ @doc("The DID resolution process confirmed that there is no current DID.")
18+ model DidNotFound {}
19+20+ @doc("The DID previously existed, but has been deactivated.")
21+ model DidDeactivated {}
22+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.resolveHandle {
4+ @doc("Resolves an atproto handle (hostname) to a DID. Does not necessarily bi-directionally verify against the the DID document.")
5+ @query
6+ @errors(HandleNotFound)
7+ op main(
8+ @doc("The handle to resolve.")
9+ @required
10+ handle: handle
11+ ): {
12+ @required did: did;
13+ };
14+15+ @doc("The resolution process confirmed that the handle does not resolve to any DID.")
16+ model HandleNotFound {}
17+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.resolveIdentity {
4+ @doc("The resolution process confirmed that the handle does not resolve to any DID.")
5+ model HandleNotFound {}
6+7+ @doc("The DID resolution process confirmed that there is no current DID.")
8+ model DidNotFound {}
9+10+ @doc("The DID previously existed, but has been deactivated.")
11+ model DidDeactivated {}
12+13+ @doc("Resolves an identity (DID or Handle) to a full identity (DID document and verified handle).")
14+ @query
15+ @errors(HandleNotFound, DidNotFound, DidDeactivated)
16+ op main(
17+ @doc("Handle or DID to resolve.")
18+ @required
19+ identifier: atIdentifier
20+ ): com.atproto.identity.defs.IdentityInfo;
21+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.identity.submitPlcOperation {
4+ @doc("Validates a PLC operation to ensure that it doesn't violate a service's constraints or get the identity into a bad state, then submits it to the PLC registry")
5+ @procedure
6+ op main(input: {
7+ @required operation: unknown;
8+ }): void;
9+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.label.defs {
4+ @doc("Metadata tag on an atproto resource (eg, repo or record).")
5+ model Label {
6+ @doc("The AT Protocol version of the label object.")
7+ ver?: integer;
8+9+ @doc("DID of the actor who created this label.")
10+ @required
11+ src: did;
12+13+ @doc("AT URI of the record, repository (account), or other resource that this label applies to.")
14+ @required
15+ uri: uri;
16+17+ @doc("Optionally, CID specifying the specific version of 'uri' resource this label applies to.")
18+ cid?: cid;
19+20+ @doc("The short string name of the value or type of this label.")
21+ @maxLength(128)
22+ @required
23+ val: string;
24+25+ @doc("If true, this is a negation label, overwriting a previous label.")
26+ neg?: boolean;
27+28+ @doc("Timestamp when this label was created.")
29+ @required
30+ cts: datetime;
31+32+ @doc("Timestamp at which this label expires (no longer applies).")
33+ exp?: datetime;
34+35+ @doc("Signature of dag-cbor encoded label.")
36+ sig?: bytes;
37+ }
38+39+ @doc("Metadata tags on an atproto record, published by the author within the record.")
40+ model SelfLabels {
41+ @maxItems(10)
42+ @required
43+ values: SelfLabel[];
44+ }
45+46+ @doc("Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.")
47+ model SelfLabel {
48+ @doc("The short string name of the value or type of this label.")
49+ @maxLength(128)
50+ @required
51+ val: string;
52+ }
53+54+ @doc("Declares a label value and its expected interpretations and behaviors.")
55+ model LabelValueDefinition {
56+ @doc("The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).")
57+ @maxLength(100)
58+ @maxGraphemes(100)
59+ @required
60+ identifier: string;
61+62+ @doc("How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.")
63+ @required
64+ severity: "inform" | "alert" | "none" | string;
65+66+ @doc("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.")
67+ @required
68+ blurs: "content" | "media" | "none" | string;
69+70+ @doc("The default setting for this label.")
71+ defaultSetting?: "ignore" | "warn" | "hide" | string = "warn";
72+73+ @doc("Does the user need to have adult content enabled in order to configure this label?")
74+ adultOnly?: boolean;
75+76+ @required
77+ locales: LabelValueDefinitionStrings[];
78+ }
79+80+ @doc("Strings which describe the label in the UI, localized into a specific language.")
81+ model LabelValueDefinitionStrings {
82+ @doc("The code of the language these strings are written in.")
83+ @required
84+ lang: language;
85+86+ @doc("A short human-readable name for the label.")
87+ @maxGraphemes(64)
88+ @maxLength(640)
89+ @required
90+ name: string;
91+92+ @doc("A longer description of what the label means and why it might be applied.")
93+ @maxGraphemes(10000)
94+ @maxLength(100000)
95+ @required
96+ description: string;
97+ }
98+99+ union LabelValue {
100+ "!hide",
101+ "!no-promote",
102+ "!warn",
103+ "!no-unauthenticated",
104+ "dmca-violation",
105+ "doxxing",
106+ "porn",
107+ "sexual",
108+ "nudity",
109+ "nsfl",
110+ "gore",
111+ string,
112+ }
113+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.label.queryLabels {
4+ @doc("Find labels relevant to the provided AT-URI patterns. Public endpoint for moderation services, though may return different or additional results with auth.")
5+ @query
6+ op main(
7+ @doc("List of AT URI patterns to match (boolean 'OR'). Each may be a prefix (ending with '*'; will match inclusive of the string leading to '*'), or a full URI.")
8+ @required
9+ uriPatterns: string[],
10+11+ @doc("Optional list of label sources (DIDs) to filter on.")
12+ sources?: did[],
13+14+ @minValue(1)
15+ @maxValue(250)
16+ limit?: int32 = 50,
17+18+ cursor?: string
19+ ): {
20+ cursor?: string;
21+ @required labels: com.atproto.label.defs.Label[];
22+ };
23+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.lexicon.schema {
4+ @doc("Representation of Lexicon schemas themselves, when published as atproto records. Note that the schema language is not defined in Lexicon; this meta schema currently only includes a single version field ('lexicon'). See the atproto specifications for description of the other expected top-level fields ('id', 'defs', etc).")
5+ @rec("nsid")
6+ model Main {
7+ @doc("Indicates the 'version' of the Lexicon language. Must be '1' for the current atproto/Lexicon schema system.")
8+ @required
9+ lexicon: integer;
10+ }
11+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.applyWrites {
4+ @doc("Indicates that the 'swapCommit' parameter did not match current commit.")
5+ model InvalidSwap {}
6+7+ @closed
8+ @inline
9+ union WriteAction {
10+ Create,
11+ Update,
12+ Delete,
13+ }
14+15+ @closed
16+ @inline
17+ union WriteResult {
18+ CreateResult,
19+ UpdateResult,
20+ DeleteResult,
21+ }
22+23+ @doc("Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.")
24+ @procedure
25+ @errors(InvalidSwap)
26+ op main(input: {
27+ @doc("The handle or DID of the repo (aka, current account).")
28+ @required
29+ repo: atIdentifier;
30+31+ @doc("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.")
32+ validate?: boolean;
33+34+ @required
35+ writes: WriteAction[];
36+37+ @doc("If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.")
38+ swapCommit?: cid;
39+ }): {
40+ commit?: com.atproto.repo.defs.CommitMeta;
41+ results?: WriteResult[];
42+ };
43+44+ @doc("Operation which creates a new record.")
45+ model Create {
46+ @required collection: nsid;
47+48+ @doc("NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility.")
49+ @maxLength(512)
50+ rkey?: recordKey;
51+52+ @required value: unknown;
53+ }
54+55+ @doc("Operation which updates an existing record.")
56+ model Update {
57+ @required collection: nsid;
58+ @required rkey: recordKey;
59+ @required value: unknown;
60+ }
61+62+ @doc("Operation which deletes an existing record.")
63+ model Delete {
64+ @required collection: nsid;
65+ @required rkey: recordKey;
66+ }
67+68+ model CreateResult {
69+ @required uri: atUri;
70+ @required cid: cid;
71+ validationStatus?: "valid" | "unknown" | string;
72+ }
73+74+ model UpdateResult {
75+ @required uri: atUri;
76+ @required cid: cid;
77+ validationStatus?: "valid" | "unknown" | string;
78+ }
79+80+ model DeleteResult {}
81+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.createRecord {
4+ @doc("Create a single new repository record. Requires auth, implemented by PDS.")
5+ @errors(InvalidSwap)
6+ @procedure
7+ op main(input: {
8+ @doc("The handle or DID of the repo (aka, current account).")
9+ @required
10+ repo: atIdentifier;
11+12+ @doc("The NSID of the record collection.")
13+ @required
14+ collection: nsid;
15+16+ @doc("The Record Key.")
17+ @maxLength(512)
18+ rkey?: recordKey;
19+20+ @doc("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.")
21+ validate?: boolean;
22+23+ @doc("The record itself. Must contain a $type field.")
24+ @required
25+ record: unknown;
26+27+ @doc("Compare and swap with the previous commit by CID.")
28+ swapCommit?: cid;
29+ }): {
30+ @required uri: atUri;
31+ @required cid: cid;
32+ commit?: com.atproto.repo.defs.CommitMeta;
33+ validationStatus?: "valid" | "unknown" | string;
34+ };
35+36+ @doc("Indicates that 'swapCommit' didn't match current repo commit.")
37+ model InvalidSwap {}
38+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.deleteRecord {
4+ @doc("Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.")
5+ @errors(InvalidSwap)
6+ @procedure
7+ op main(input: {
8+ @doc("The handle or DID of the repo (aka, current account).")
9+ @required
10+ repo: atIdentifier;
11+12+ @doc("The NSID of the record collection.")
13+ @required
14+ collection: nsid;
15+16+ @doc("The Record Key.")
17+ @required
18+ rkey: recordKey;
19+20+ @doc("Compare and swap with the previous record by CID.")
21+ swapRecord?: cid;
22+23+ @doc("Compare and swap with the previous commit by CID.")
24+ swapCommit?: cid;
25+ }): {
26+ commit?: com.atproto.repo.defs.CommitMeta;
27+ };
28+29+ model InvalidSwap {}
30+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.describeRepo {
4+ @doc("Get information about an account and repository, including the list of collections. Does not require auth.")
5+ @query
6+ op main(
7+ @doc("The handle or DID of the repo.")
8+ @required
9+ repo: atIdentifier
10+ ): {
11+ @required handle: handle;
12+ @required did: did;
13+14+ @doc("The complete DID document for this account.")
15+ @required
16+ didDoc: unknown;
17+18+ @doc("List of all the collections (NSIDs) for which this repo contains at least one record.")
19+ @required
20+ collections: nsid[];
21+22+ @doc("Indicates if handle is currently valid (resolves bi-directionally)")
23+ @required
24+ handleIsCorrect: boolean;
25+ };
26+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.getRecord {
4+ @doc("Get a single record from a repository. Does not require auth.")
5+ @query
6+ @errors(RecordNotFound)
7+ op main(
8+ @doc("The handle or DID of the repo.")
9+ @required
10+ repo: atIdentifier,
11+12+ @doc("The NSID of the record collection.")
13+ @required
14+ collection: nsid,
15+16+ @doc("The Record Key.")
17+ @required
18+ rkey: recordKey,
19+20+ @doc("The CID of the version of the record. If not specified, then return the most recent version.")
21+ cid?: cid
22+ ): {
23+ @required uri: atUri;
24+ cid?: cid;
25+ @required value: unknown;
26+ };
27+28+ model RecordNotFound {}
29+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.importRepo {
4+ @doc("Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.")
5+ @procedure
6+ op main(
7+ @encoding("application/vnd.ipld.car")
8+ input: void
9+ ): void;
10+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.listRecords {
4+ @doc("List a range of records in a repository, matching a specific collection. Does not require auth.")
5+ @query
6+ op main(
7+ @doc("The handle or DID of the repo.")
8+ @required
9+ repo: atIdentifier,
10+11+ @doc("The NSID of the record type.")
12+ @required
13+ collection: nsid,
14+15+ @doc("The number of records to return.")
16+ @minValue(1)
17+ @maxValue(100)
18+ limit?: int32 = 50,
19+20+ cursor?: string,
21+22+ @doc("Flag to reverse the order of the returned records.")
23+ reverse?: boolean
24+ ): {
25+ cursor?: string;
26+ @required records: Record[];
27+ };
28+29+ model Record {
30+ @required uri: atUri;
31+ @required cid: cid;
32+ @required value: unknown;
33+ }
34+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.putRecord {
4+ @doc("Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.")
5+ @errors(InvalidSwap)
6+ @procedure
7+ op main(input: {
8+ @doc("The handle or DID of the repo (aka, current account).")
9+ @required
10+ repo: atIdentifier;
11+12+ @doc("The NSID of the record collection.")
13+ @required
14+ collection: nsid;
15+16+ @doc("The Record Key.")
17+ @maxLength(512)
18+ @required
19+ rkey: recordKey;
20+21+ @doc("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.")
22+ validate?: boolean;
23+24+ @doc("The record to write.")
25+ @required
26+ record: unknown;
27+28+ @doc("Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation")
29+ swapRecord?: cid | null;
30+31+ @doc("Compare and swap with the previous commit by CID.")
32+ swapCommit?: cid;
33+ }): {
34+ @required uri: atUri;
35+ @required cid: cid;
36+ commit?: com.atproto.repo.defs.CommitMeta;
37+ validationStatus?: "valid" | "unknown" | string;
38+ };
39+40+ model InvalidSwap {}
41+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.repo.uploadBlob {
4+ @doc("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.")
5+ @procedure
6+ op main(
7+ @encoding("*/*")
8+ input: void
9+ ): {
10+ @required blob: Blob<#[], 0>;
11+ };
12+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.activateAccount {
4+ @doc("Activates a currently deactivated account. Used to finalize account migration after the account's repo is imported and identity is setup.")
5+ @procedure
6+ op main(): void;
7+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.checkAccountStatus {
4+ @doc("Returns the status of an account, especially as pertaining to import or recovery. Can be called many times over the course of an account migration. Requires auth and can only be called pertaining to oneself.")
5+ @query
6+ op main(): {
7+ @required activated: boolean;
8+ @required validDid: boolean;
9+ @required repoCommit: cid;
10+ @required repoRev: string;
11+ @required repoBlocks: integer;
12+ @required indexedRecords: integer;
13+ @required privateStateValues: integer;
14+ @required expectedBlobs: integer;
15+ @required importedBlobs: integer;
16+ };
17+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.createAccount {
4+ model InvalidHandle {}
5+ model InvalidPassword {}
6+ model InvalidInviteCode {}
7+ model HandleNotAvailable {}
8+ model UnsupportedDomain {}
9+ model UnresolvableDid {}
10+ model IncompatibleDidDoc {}
11+12+ @doc("Account login session returned on successful account creation.")
13+ @inline
14+ model Output {
15+ @required accessJwt: string;
16+ @required refreshJwt: string;
17+ @required handle: handle;
18+19+ @doc("The DID of the new account.")
20+ @required
21+ did: did;
22+23+ @doc("Complete DID document.")
24+ didDoc?: unknown;
25+ }
26+27+ @doc("Create an account. Implemented by PDS.")
28+ @procedure
29+ @errors(InvalidHandle, InvalidPassword, InvalidInviteCode, HandleNotAvailable, UnsupportedDomain, UnresolvableDid, IncompatibleDidDoc)
30+ op main(input: {
31+ email?: string;
32+33+ @doc("Requested handle for the account.")
34+ @required
35+ handle: handle;
36+37+ @doc("Pre-existing atproto DID, being imported to a new account.")
38+ did?: did;
39+40+ inviteCode?: string;
41+ verificationCode?: string;
42+ verificationPhone?: string;
43+44+ @doc("Initial account password. May need to meet instance-specific password strength requirements.")
45+ password?: string;
46+47+ @doc("DID PLC rotation key (aka, recovery key) to be included in PLC creation operation.")
48+ recoveryKey?: string;
49+50+ @doc("A signed DID PLC operation to be submitted as part of importing an existing account to this instance. NOTE: this optional field may be updated when full account migration is implemented.")
51+ plcOp?: unknown;
52+ }): Output;
53+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.createSession {
4+ model AccountTakedown {}
5+6+ model AuthFactorTokenRequired {}
7+8+ @doc("Create an authentication session.")
9+ @procedure
10+ @errors(AccountTakedown, AuthFactorTokenRequired)
11+ op main(input: {
12+ @doc("Handle or other identifier supported by the server for the authenticating user.")
13+ @required
14+ identifier: string;
15+16+ @required password: string;
17+18+ authFactorToken?: string;
19+20+ @doc("When true, instead of throwing error for takendown accounts, a valid response with a narrow scoped token will be returned")
21+ allowTakendown?: boolean;
22+ }): {
23+ @required accessJwt: string;
24+ @required refreshJwt: string;
25+ @required handle: handle;
26+ @required did: did;
27+ didDoc?: unknown;
28+ email?: string;
29+ emailConfirmed?: boolean;
30+ emailAuthFactor?: boolean;
31+ active?: boolean;
32+33+ @doc("If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.")
34+ status?: "takendown" | "suspended" | "deactivated" | string;
35+ };
36+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.deactivateAccount {
4+ @doc("Deactivates a currently active account. Stops serving of repo, and future writes to repo until reactivated. Used to finalize account migration with the old host after the account has been activated on the new host.")
5+ @procedure
6+ op main(input: {
7+ @doc("A recommendation to server as to how long they should hold onto the deactivated account before deleting.")
8+ deleteAfter?: datetime;
9+ }): void;
10+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.deleteAccount {
4+ model ExpiredToken {}
5+ model InvalidToken {}
6+7+ @doc("Delete an actor's account with a token and password. Can only be called after requesting a deletion token. Requires auth.")
8+ @procedure
9+ @errors(ExpiredToken, InvalidToken)
10+ op main(input: {
11+ @required did: did;
12+ @required password: string;
13+ @required token: string;
14+ }): void;
15+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.describeServer {
4+ @doc("Describes the server's account creation requirements and capabilities. Implemented by PDS.")
5+ @query
6+ op main(): {
7+ @required did: did;
8+9+ @doc("If true, an invite code must be supplied to create an account on this instance.")
10+ inviteCodeRequired?: boolean;
11+12+ @doc("If true, a phone verification token must be supplied to create an account on this instance.")
13+ phoneVerificationRequired?: boolean;
14+15+ @doc("List of domain suffixes that can be used in account handles.")
16+ @required
17+ availableUserDomains: string[];
18+19+ @doc("URLs of service policy documents.")
20+ links?: Links;
21+22+ @doc("Contact information")
23+ contact?: Contact;
24+ };
25+26+ model Links {
27+ privacyPolicy?: uri;
28+ termsOfService?: uri;
29+ }
30+31+ model Contact {
32+ email?: string;
33+ }
34+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.getServiceAuth {
4+ @doc("Indicates that the requested expiration date is not a valid. May be in the past or may be reliant on the requested scopes.")
5+ model BadExpiration {}
6+7+ @doc("Get a signed token on behalf of the requesting DID for the requested service.")
8+ @query
9+ @errors(BadExpiration)
10+ op main(
11+ @doc("The DID of the service that the token will be used to authenticate with")
12+ @required
13+ aud: did,
14+15+ @doc("The time in Unix Epoch seconds that the JWT expires. Defaults to 60 seconds in the future. The service may enforce certain time bounds on tokens depending on the requested scope.")
16+ exp?: integer,
17+18+ @doc("Lexicon (XRPC) method to bind the requested token to")
19+ lxm?: nsid
20+ ): {
21+ @required token: string;
22+ };
23+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.getSession {
4+ @doc("Get information about the current auth session. Requires auth.")
5+ @query
6+ op main(): {
7+ @required handle: handle;
8+ @required did: did;
9+ email?: string;
10+ emailConfirmed?: boolean;
11+ emailAuthFactor?: boolean;
12+ didDoc?: unknown;
13+ active?: boolean;
14+15+ @doc("If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.")
16+ status?: "takendown" | "suspended" | "deactivated" | string;
17+ };
18+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.requestAccountDelete {
4+ @doc("Initiate a user account deletion via email.")
5+ @procedure
6+ op main(): void;
7+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.requestEmailConfirmation {
4+ @doc("Request an email with a code to confirm ownership of email.")
5+ @procedure
6+ op main(): void;
7+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.server.reserveSigningKey {
4+ @doc("Reserve a repo signing key, for use with account creation. Necessary so that a DID PLC update operation can be constructed during an account migraiton. Public and does not require auth; implemented by PDS. NOTE: this endpoint may change when full account migration is implemented.")
5+ @procedure
6+ op main(input: {
7+ @doc("The DID to reserve a key for.")
8+ did?: did;
9+ }): {
10+ @doc("The public key for the reserved signing key, in did:key serialization.")
11+ @required
12+ signingKey: string;
13+ };
14+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.getBlob {
4+ @doc("Get a blob associated with a given account. Returns the full blob as originally uploaded. Does not require auth; implemented by PDS.")
5+ @query
6+ @encoding("*/*")
7+ @errors(BlobNotFound, RepoNotFound, RepoTakendown, RepoSuspended, RepoDeactivated)
8+ op main(
9+ @doc("The DID of the account.")
10+ @required
11+ did: did,
12+13+ @doc("The CID of the blob to fetch")
14+ @required
15+ cid: cid
16+ ): void;
17+18+ model BlobNotFound {}
19+ model RepoNotFound {}
20+ model RepoTakendown {}
21+ model RepoSuspended {}
22+ model RepoDeactivated {}
23+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.getBlocks {
4+ @doc("Get data blocks from a given repo, by CID. For example, intermediate MST nodes, or records. Does not require auth; implemented by PDS.")
5+ @query
6+ @encoding("application/vnd.ipld.car")
7+ @errors(BlockNotFound, RepoNotFound, RepoTakendown, RepoSuspended, RepoDeactivated)
8+ op main(
9+ @doc("The DID of the repo.")
10+ @required
11+ did: did,
12+13+ @required cids: cid[]
14+ ): void;
15+16+ model BlockNotFound {}
17+ model RepoNotFound {}
18+ model RepoTakendown {}
19+ model RepoSuspended {}
20+ model RepoDeactivated {}
21+}
···1+import "@tylex/emitter";
2+import "./defs.tsp";
3+4+namespace com.atproto.sync.getHostStatus {
5+ @doc("Returns information about a specified upstream host, as consumed by the server. Implemented by relays.")
6+ @query
7+ @errors(HostNotFound)
8+ op main(
9+ @doc("Hostname of the host (eg, PDS or relay) being queried.")
10+ @required
11+ hostname: string
12+ ): {
13+ @required hostname: string;
14+15+ @doc("Recent repo stream event sequence number. May be delayed from actual stream processing (eg, persisted cursor not in-memory cursor).")
16+ seq?: integer;
17+18+ @doc("Number of accounts on the server which are associated with the upstream host. Note that the upstream may actually have more accounts.")
19+ accountCount?: integer;
20+21+ status?: com.atproto.sync.defs.HostStatus;
22+ };
23+24+ model HostNotFound {}
25+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.getLatestCommit {
4+ @doc("Get the current commit CID & revision of the specified repo. Does not require auth.")
5+ @query
6+ @errors(RepoNotFound, RepoTakendown, RepoSuspended, RepoDeactivated)
7+ op main(
8+ @doc("The DID of the repo.")
9+ @required
10+ did: did
11+ ): {
12+ @required cid: cid;
13+ @required rev: tid;
14+ };
15+16+ model RepoNotFound {}
17+ model RepoTakendown {}
18+ model RepoSuspended {}
19+ model RepoDeactivated {}
20+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.getRecord {
4+ @doc("Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.")
5+ @query
6+ @encoding("application/vnd.ipld.car")
7+ @errors(RecordNotFound, RepoNotFound, RepoTakendown, RepoSuspended, RepoDeactivated)
8+ op main(
9+ @doc("The DID of the repo.")
10+ @required
11+ did: did,
12+13+ @required collection: nsid,
14+15+ @doc("Record Key")
16+ @required
17+ rkey: recordKey
18+ ): void;
19+20+ model RecordNotFound {}
21+ model RepoNotFound {}
22+ model RepoTakendown {}
23+ model RepoSuspended {}
24+ model RepoDeactivated {}
25+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.getRepo {
4+ @doc("Download a repository export as CAR file. Optionally only a 'diff' since a previous revision. Does not require auth; implemented by PDS.")
5+ @query
6+ @encoding("application/vnd.ipld.car")
7+ @errors(RepoNotFound, RepoTakendown, RepoSuspended, RepoDeactivated)
8+ op main(
9+ @doc("The DID of the repo.")
10+ @required
11+ did: did,
12+13+ @doc("The revision ('rev') of the repo to create a diff from.")
14+ since?: tid
15+ ): void;
16+17+ model RepoNotFound {}
18+ model RepoTakendown {}
19+ model RepoSuspended {}
20+ model RepoDeactivated {}
21+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.getRepoStatus {
4+ @doc("Get the hosting status for a repository, on this server. Expected to be implemented by PDS and Relay.")
5+ @query
6+ @errors(RepoNotFound)
7+ op main(
8+ @doc("The DID of the repo.")
9+ @required
10+ did: did
11+ ): {
12+ @required did: did;
13+ @required active: boolean;
14+15+ @doc("If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.")
16+ status?: "takendown" | "suspended" | "deleted" | "deactivated" | "desynchronized" | "throttled" | string;
17+18+ @doc("Optional field, the current rev of the repo, if active=true")
19+ rev?: tid;
20+ };
21+22+ model RepoNotFound {}
23+}
···1+import "@tylex/emitter";
2+import "./defs.tsp";
3+4+namespace com.atproto.sync.listHosts {
5+ @doc("Enumerates upstream hosts (eg, PDS or relay instances) that this service consumes from. Implemented by relays.")
6+ @query
7+ op main(
8+ @minValue(1)
9+ @maxValue(1000)
10+ limit?: int32 = 200,
11+12+ cursor?: string
13+ ): {
14+ cursor?: string;
15+16+ @doc("Sort order is not formally specified. Recommended order is by time host was first seen by the server, with oldest first.")
17+ @required
18+ hosts: Host[];
19+ };
20+21+ model Host {
22+ @doc("hostname of server; not a URL (no scheme)")
23+ @required
24+ hostname: string;
25+26+ @doc("Recent repo stream event sequence number. May be delayed from actual stream processing (eg, persisted cursor not in-memory cursor).")
27+ seq?: integer;
28+29+ accountCount?: integer;
30+ status?: com.atproto.sync.defs.HostStatus;
31+ }
32+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.listRepos {
4+ @doc("Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.")
5+ @query
6+ op main(
7+ @minValue(1)
8+ @maxValue(1000)
9+ limit?: int32 = 500,
10+11+ cursor?: string
12+ ): {
13+ cursor?: string;
14+ @required repos: Repo[];
15+ };
16+17+ model Repo {
18+ @required did: did;
19+20+ @doc("Current repo commit CID")
21+ @required
22+ head: cid;
23+24+ @required rev: tid;
25+ active?: boolean;
26+27+ @doc("If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.")
28+ status?: "takendown" | "suspended" | "deleted" | "deactivated" | "desynchronized" | "throttled" | string;
29+ }
30+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.listReposByCollection {
4+ @doc("Enumerates all the DIDs which have records with the given collection NSID.")
5+ @query
6+ op main(
7+ @required collection: nsid,
8+9+ @doc("Maximum size of response set. Recommend setting a large maximum (1000+) when enumerating large DID lists.")
10+ @minValue(1)
11+ @maxValue(2000)
12+ limit?: int32 = 500,
13+14+ cursor?: string
15+ ): {
16+ cursor?: string;
17+ @required repos: Repo[];
18+ };
19+20+ model Repo {
21+ @required did: did;
22+ }
23+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.notifyOfUpdate {
4+ @doc("Notify a crawling service of a recent update, and that crawling should resume. Intended use is after a gap between repo stream events caused the crawling service to disconnect. Does not require auth; implemented by Relay. DEPRECATED: just use com.atproto.sync.requestCrawl")
5+ @procedure
6+ op main(input: {
7+ @doc("Hostname of the current service (usually a PDS) that is notifying of update.")
8+ @required
9+ hostname: string;
10+ }): void;
11+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.requestCrawl {
4+ @doc("Request a service to persistently crawl hosted repos. Expected use is new PDS instances declaring their existence to Relays. Does not require auth.")
5+ @procedure
6+ @errors(HostBanned)
7+ op main(input: {
8+ @doc("Hostname of the current service (eg, PDS) that is requesting to be crawled.")
9+ @required
10+ hostname: string;
11+ }): void;
12+13+ model HostBanned {}
14+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.sync.subscribeRepos {
4+ @subscription
5+ @errors(FutureCursor, ConsumerTooSlow)
6+ @doc("Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.")
7+ op main(
8+ @doc("The last known event seq number to backfill from.")
9+ cursor?: integer
10+ ): (Commit | Sync | Identity | Account | Info | unknown);
11+12+ model FutureCursor {}
13+14+ @doc("If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection.")
15+ model ConsumerTooSlow {}
16+17+ @doc("Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.")
18+ model Commit {
19+ @doc("The stream sequence number of this message.")
20+ @required
21+ seq: integer;
22+23+ @doc("DEPRECATED -- unused")
24+ @required
25+ rebase: boolean;
26+27+ @doc("DEPRECATED -- replaced by #sync event and data limits. Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data.")
28+ @required
29+ tooBig: boolean;
30+31+ @doc("The repo this event comes from. Note that all other message types name this field 'did'.")
32+ @required
33+ repo: did;
34+35+ @doc("Repo commit object CID.")
36+ @required
37+ commit: cidLink;
38+39+ @doc("The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event.")
40+ @required
41+ rev: tid;
42+43+ @doc("The rev of the last emitted commit from this repo (if any).")
44+ @required
45+ since: tid | null;
46+47+ @doc("CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list.")
48+ @maxBytes(2000000)
49+ @required
50+ blocks: bytes;
51+52+ @maxItems(200)
53+ @required
54+ @doc("List of repo mutation operations in this commit (eg, records created, updated, or deleted).")
55+ ops: RepoOp[];
56+57+ @doc("DEPRECATED -- will soon always be empty. List of new blobs (by CID) referenced by records in this commit.")
58+ @required blobs: cidLink[];
59+60+ @doc("The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose.")
61+ prevData?: cidLink;
62+63+ @doc("Timestamp of when this message was originally broadcast.")
64+ @required
65+ time: datetime;
66+ }
67+68+ @doc("Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository.")
69+ model Sync {
70+ @doc("The stream sequence number of this message.")
71+ @required
72+ seq: integer;
73+74+ @doc("The account this repo event corresponds to. Must match that in the commit object.")
75+ @required
76+ did: did;
77+78+ @doc("CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'.")
79+ @maxBytes(10000)
80+ @required
81+ blocks: bytes;
82+83+ @doc("The rev of the commit. This value must match that in the commit object.")
84+ @required
85+ rev: string;
86+87+ @doc("Timestamp of when this message was originally broadcast.")
88+ @required
89+ time: datetime;
90+ }
91+92+ @doc("Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.")
93+ model Identity {
94+ @required seq: integer;
95+ @required did: did;
96+ @required time: datetime;
97+98+ @doc("The current handle for the account, or 'handle.invalid' if validation fails. This field is optional, might have been validated or passed-through from an upstream source. Semantics and behaviors for PDS vs Relay may evolve in the future; see atproto specs for more details.")
99+ handle?: handle;
100+ }
101+102+ @doc("Represents a change to an account's status on a host (eg, PDS or Relay). The semantics of this event are that the status is at the host which emitted the event, not necessarily that at the currently active PDS. Eg, a Relay takedown would emit a takedown with active=false, even if the PDS is still active.")
103+ model Account {
104+ @required seq: integer;
105+ @required did: did;
106+ @required time: datetime;
107+108+ @doc("Indicates that the account has a repository which can be fetched from the host that emitted this event.")
109+ @required
110+ active: boolean;
111+112+ @doc("If active=false, this optional field indicates a reason for why the account is not active.")
113+ status?: "takendown" | "suspended" | "deleted" | "deactivated" | "desynchronized" | "throttled" | string;
114+ }
115+116+ model Info {
117+ @required name: "OutdatedCursor" | string;
118+ message?: string;
119+ }
120+121+ @doc("A repo operation, ie a mutation of a single record.")
122+ model RepoOp {
123+ @required action: "create" | "update" | "delete" | string;
124+ @required path: string;
125+126+ @doc("For creates and updates, the new record CID. For deletions, null.")
127+ @required
128+ cid: cidLink | null;
129+130+ @doc("For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined.")
131+ prev?: cidLink;
132+ }
133+}
···1+import "@tylex/emitter";
2+3+namespace com.atproto.temp.checkHandleAvailability {
4+ @doc("An invalid email was provided.")
5+ model InvalidEmail {}
6+7+ @doc("Indicates the provided handle is available.")
8+ model ResultAvailable {}
9+10+ @doc("Indicates the provided handle is unavailable and gives suggestions of available handles.")
11+ model ResultUnavailable {
12+ @doc("List of suggested handles based on the provided inputs.")
13+ @required
14+ suggestions: Suggestion[];
15+ }
16+17+ model Suggestion {
18+ @required handle: handle;
19+20+ @doc("Method used to build this suggestion. Should be considered opaque to clients. Can be used for metrics.")
21+ @required
22+ method: string;
23+ }
24+25+ @doc("Checks whether the provided handle is available. If the handle is not available, available suggestions will be returned. Optional inputs will be used to generate suggestions.")
26+ @query
27+ @errors(InvalidEmail)
28+ op main(
29+ @doc("Tentative handle. Will be checked for availability or used to build handle suggestions.")
30+ handle: handle,
31+32+ @doc("User-provided email. Might be used to build handle suggestions.")
33+ email?: string,
34+35+ @doc("User-provided birth date. Might be used to build handle suggestions.")
36+ birthDate?: datetime
37+ ): {
38+ @doc("Echo of the input handle.")
39+ @required
40+ handle: handle;
41+42+ @required result: ResultAvailable | ResultUnavailable;
43+ };
44+}
···1+import "@tylex/emitter";
2+3+namespace `pub`.leaflet.richtext.facet {
4+ @doc("Annotation of a sub-string within rich text.")
5+ model Main {
6+ @required index: ByteSlice;
7+ @required features: (Link | Code | Highlight | Underline | Strikethrough | Id | Bold | Italic | unknown)[];
8+ }
9+10+ @doc("Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.")
11+ model ByteSlice {
12+ @minValue(0)
13+ @required
14+ byteStart: integer;
15+16+ @minValue(0)
17+ @required
18+ byteEnd: integer;
19+ }
20+21+ @doc("Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.")
22+ model Link {
23+ @required uri: uri;
24+ }
25+26+ @doc("Facet feature for inline code.")
27+ model Code {}
28+29+ @doc("Facet feature for highlighted text.")
30+ model Highlight {}
31+32+ @doc("Facet feature for underline markup")
33+ model Underline {}
34+35+ @doc("Facet feature for strikethrough markup")
36+ model Strikethrough {}
37+38+ @doc("Facet feature for an identifier. Used for linking to a segment")
39+ model Id {
40+ id?: string;
41+ }
42+43+ @doc("Facet feature for bold text")
44+ model Bold {}
45+46+ @doc("Facet feature for italic text")
47+ model Italic {}
48+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.identity.refreshIdentity",
4+ "defs": {
5+ "main": {
6+ "type": "procedure",
7+ "description": "Request that the server re-resolve an identity (DID and handle). The server may ignore this request, or require authentication, depending on the role, implementation, and policy of the server.",
8+ "input": {
9+ "encoding": "application/json",
10+ "schema": {
11+ "type": "object",
12+ "required": ["identifier"],
13+ "properties": {
14+ "identifier": {
15+ "type": "string",
16+ "format": "at-identifier"
17+ }
18+ }
19+ }
20+ },
21+ "output": {
22+ "encoding": "application/json",
23+ "schema": {
24+ "type": "ref",
25+ "ref": "com.atproto.identity.defs#identityInfo"
26+ }
27+ },
28+ "errors": [
29+ {
30+ "name": "HandleNotFound",
31+ "description": "The resolution process confirmed that the handle does not resolve to any DID."
32+ },
33+ {
34+ "name": "DidNotFound",
35+ "description": "The DID resolution process confirmed that there is no current DID."
36+ },
37+ {
38+ "name": "DidDeactivated",
39+ "description": "The DID previously existed, but has been deactivated."
40+ }
41+ ]
42+ }
43+ }
44+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.identity.requestPlcOperationSignature",
4+ "defs": {
5+ "main": {
6+ "type": "procedure",
7+ "description": "Request an email with a code to in order to request a signed PLC operation. Requires Auth."
8+ }
9+ }
10+}
···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+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.lexicon.schema",
4+ "defs": {
5+ "main": {
6+ "type": "record",
7+ "description": "Representation of Lexicon schemas themselves, when published as atproto records. Note that the schema language is not defined in Lexicon; this meta schema currently only includes a single version field ('lexicon'). See the atproto specifications for description of the other expected top-level fields ('id', 'defs', etc).",
8+ "key": "nsid",
9+ "record": {
10+ "type": "object",
11+ "required": ["lexicon"],
12+ "properties": {
13+ "lexicon": {
14+ "type": "integer",
15+ "description": "Indicates the 'version' of the Lexicon language. Must be '1' for the current atproto/Lexicon schema system."
16+ }
17+ }
18+ }
19+ }
20+ }
21+}
···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+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.server.activateAccount",
4+ "defs": {
5+ "main": {
6+ "type": "procedure",
7+ "description": "Activates a currently deactivated account. Used to finalize account migration after the account's repo is imported and identity is setup."
8+ }
9+ }
10+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.server.deactivateAccount",
4+ "defs": {
5+ "main": {
6+ "type": "procedure",
7+ "description": "Deactivates a currently active account. Stops serving of repo, and future writes to repo until reactivated. Used to finalize account migration with the old host after the account has been activated on the new host.",
8+ "input": {
9+ "encoding": "application/json",
10+ "schema": {
11+ "type": "object",
12+ "properties": {
13+ "deleteAfter": {
14+ "type": "string",
15+ "format": "datetime",
16+ "description": "A recommendation to server as to how long they should hold onto the deactivated account before deleting."
17+ }
18+ }
19+ }
20+ }
21+ }
22+ }
23+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.server.getServiceAuth",
4+ "defs": {
5+ "main": {
6+ "type": "query",
7+ "description": "Get a signed token on behalf of the requesting DID for the requested service.",
8+ "parameters": {
9+ "type": "params",
10+ "required": ["aud"],
11+ "properties": {
12+ "aud": {
13+ "type": "string",
14+ "format": "did",
15+ "description": "The DID of the service that the token will be used to authenticate with"
16+ },
17+ "exp": {
18+ "type": "integer",
19+ "description": "The time in Unix Epoch seconds that the JWT expires. Defaults to 60 seconds in the future. The service may enforce certain time bounds on tokens depending on the requested scope."
20+ },
21+ "lxm": {
22+ "type": "string",
23+ "format": "nsid",
24+ "description": "Lexicon (XRPC) method to bind the requested token to"
25+ }
26+ }
27+ },
28+ "output": {
29+ "encoding": "application/json",
30+ "schema": {
31+ "type": "object",
32+ "required": ["token"],
33+ "properties": {
34+ "token": {
35+ "type": "string"
36+ }
37+ }
38+ }
39+ },
40+ "errors": [
41+ {
42+ "name": "BadExpiration",
43+ "description": "Indicates that the requested expiration date is not a valid. May be in the past or may be reliant on the requested scopes."
44+ }
45+ ]
46+ }
47+ }
48+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.server.reserveSigningKey",
4+ "defs": {
5+ "main": {
6+ "type": "procedure",
7+ "description": "Reserve a repo signing key, for use with account creation. Necessary so that a DID PLC update operation can be constructed during an account migraiton. Public and does not require auth; implemented by PDS. NOTE: this endpoint may change when full account migration is implemented.",
8+ "input": {
9+ "encoding": "application/json",
10+ "schema": {
11+ "type": "object",
12+ "properties": {
13+ "did": {
14+ "type": "string",
15+ "format": "did",
16+ "description": "The DID to reserve a key for."
17+ }
18+ }
19+ }
20+ },
21+ "output": {
22+ "encoding": "application/json",
23+ "schema": {
24+ "type": "object",
25+ "required": ["signingKey"],
26+ "properties": {
27+ "signingKey": {
28+ "type": "string",
29+ "description": "The public key for the reserved signing key, in did:key serialization."
30+ }
31+ }
32+ }
33+ }
34+ }
35+ }
36+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.sync.notifyOfUpdate",
4+ "defs": {
5+ "main": {
6+ "type": "procedure",
7+ "description": "Notify a crawling service of a recent update, and that crawling should resume. Intended use is after a gap between repo stream events caused the crawling service to disconnect. Does not require auth; implemented by Relay. DEPRECATED: just use com.atproto.sync.requestCrawl",
8+ "input": {
9+ "encoding": "application/json",
10+ "schema": {
11+ "type": "object",
12+ "required": ["hostname"],
13+ "properties": {
14+ "hostname": {
15+ "type": "string",
16+ "description": "Hostname of the current service (usually a PDS) that is notifying of update."
17+ }
18+ }
19+ }
20+ }
21+ }
22+ }
23+}
···1+{
2+ "lexicon": 1,
3+ "id": "com.atproto.sync.subscribeRepos",
4+ "defs": {
5+ "main": {
6+ "type": "subscription",
7+ "description": "Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.",
8+ "parameters": {
9+ "type": "params",
10+ "properties": {
11+ "cursor": {
12+ "type": "integer",
13+ "description": "The last known event seq number to backfill from."
14+ }
15+ }
16+ },
17+ "message": {
18+ "schema": {
19+ "type": "union",
20+ "refs": ["#commit", "#sync", "#identity", "#account", "#info"]
21+ }
22+ },
23+ "errors": [
24+ { "name": "FutureCursor" },
25+ {
26+ "name": "ConsumerTooSlow",
27+ "description": "If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection."
28+ }
29+ ]
30+ },
31+ "commit": {
32+ "type": "object",
33+ "description": "Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.",
34+ "required": [
35+ "seq",
36+ "rebase",
37+ "tooBig",
38+ "repo",
39+ "commit",
40+ "rev",
41+ "since",
42+ "blocks",
43+ "ops",
44+ "blobs",
45+ "time"
46+ ],
47+ "nullable": ["since"],
48+ "properties": {
49+ "seq": {
50+ "type": "integer",
51+ "description": "The stream sequence number of this message."
52+ },
53+ "rebase": { "type": "boolean", "description": "DEPRECATED -- unused" },
54+ "tooBig": {
55+ "type": "boolean",
56+ "description": "DEPRECATED -- replaced by #sync event and data limits. Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data."
57+ },
58+ "repo": {
59+ "type": "string",
60+ "format": "did",
61+ "description": "The repo this event comes from. Note that all other message types name this field 'did'."
62+ },
63+ "commit": {
64+ "type": "cid-link",
65+ "description": "Repo commit object CID."
66+ },
67+ "rev": {
68+ "type": "string",
69+ "format": "tid",
70+ "description": "The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event."
71+ },
72+ "since": {
73+ "type": "string",
74+ "format": "tid",
75+ "description": "The rev of the last emitted commit from this repo (if any)."
76+ },
77+ "blocks": {
78+ "type": "bytes",
79+ "description": "CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list.",
80+ "maxLength": 2000000
81+ },
82+ "ops": {
83+ "type": "array",
84+ "description": "List of repo mutation operations in this commit (eg, records created, updated, or deleted).",
85+ "items": {
86+ "type": "ref",
87+ "ref": "#repoOp"
88+ },
89+ "maxLength": 200
90+ },
91+ "blobs": {
92+ "type": "array",
93+ "description": "DEPRECATED -- will soon always be empty. List of new blobs (by CID) referenced by records in this commit.",
94+ "items": {
95+ "type": "cid-link"
96+ }
97+ },
98+ "prevData": {
99+ "type": "cid-link",
100+ "description": "The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose."
101+ },
102+ "time": {
103+ "type": "string",
104+ "format": "datetime",
105+ "description": "Timestamp of when this message was originally broadcast."
106+ }
107+ }
108+ },
109+ "sync": {
110+ "type": "object",
111+ "description": "Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository.",
112+ "required": ["seq", "did", "blocks", "rev", "time"],
113+ "properties": {
114+ "seq": {
115+ "type": "integer",
116+ "description": "The stream sequence number of this message."
117+ },
118+ "did": {
119+ "type": "string",
120+ "format": "did",
121+ "description": "The account this repo event corresponds to. Must match that in the commit object."
122+ },
123+ "blocks": {
124+ "type": "bytes",
125+ "description": "CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'.",
126+ "maxLength": 10000
127+ },
128+ "rev": {
129+ "type": "string",
130+ "description": "The rev of the commit. This value must match that in the commit object."
131+ },
132+ "time": {
133+ "type": "string",
134+ "format": "datetime",
135+ "description": "Timestamp of when this message was originally broadcast."
136+ }
137+ }
138+ },
139+ "identity": {
140+ "type": "object",
141+ "description": "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.",
142+ "required": ["seq", "did", "time"],
143+ "properties": {
144+ "seq": { "type": "integer" },
145+ "did": { "type": "string", "format": "did" },
146+ "time": { "type": "string", "format": "datetime" },
147+ "handle": {
148+ "type": "string",
149+ "format": "handle",
150+ "description": "The current handle for the account, or 'handle.invalid' if validation fails. This field is optional, might have been validated or passed-through from an upstream source. Semantics and behaviors for PDS vs Relay may evolve in the future; see atproto specs for more details."
151+ }
152+ }
153+ },
154+ "account": {
155+ "type": "object",
156+ "description": "Represents a change to an account's status on a host (eg, PDS or Relay). The semantics of this event are that the status is at the host which emitted the event, not necessarily that at the currently active PDS. Eg, a Relay takedown would emit a takedown with active=false, even if the PDS is still active.",
157+ "required": ["seq", "did", "time", "active"],
158+ "properties": {
159+ "seq": { "type": "integer" },
160+ "did": { "type": "string", "format": "did" },
161+ "time": { "type": "string", "format": "datetime" },
162+ "active": {
163+ "type": "boolean",
164+ "description": "Indicates that the account has a repository which can be fetched from the host that emitted this event."
165+ },
166+ "status": {
167+ "type": "string",
168+ "description": "If active=false, this optional field indicates a reason for why the account is not active.",
169+ "knownValues": [
170+ "takendown",
171+ "suspended",
172+ "deleted",
173+ "deactivated",
174+ "desynchronized",
175+ "throttled"
176+ ]
177+ }
178+ }
179+ },
180+ "info": {
181+ "type": "object",
182+ "required": ["name"],
183+ "properties": {
184+ "name": {
185+ "type": "string",
186+ "knownValues": ["OutdatedCursor"]
187+ },
188+ "message": {
189+ "type": "string"
190+ }
191+ }
192+ },
193+ "repoOp": {
194+ "type": "object",
195+ "description": "A repo operation, ie a mutation of a single record.",
196+ "required": ["action", "path", "cid"],
197+ "nullable": ["cid"],
198+ "properties": {
199+ "action": {
200+ "type": "string",
201+ "knownValues": ["create", "update", "delete"]
202+ },
203+ "path": { "type": "string" },
204+ "cid": {
205+ "type": "cid-link",
206+ "description": "For creates and updates, the new record CID. For deletions, null."
207+ },
208+ "prev": {
209+ "type": "cid-link",
210+ "description": "For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined."
211+ }
212+ }
213+ }
214+ }
215+}
···1+# Tylex Website
2+3+Landing page for tylex - TypeSpec for AT Protocol Lexicons.
4+5+## Features
6+7+- **Live Examples**: TypeSpec examples are compiled during build to show real Lexicon JSON output
8+- **Syntax Highlighting**: Using Shiki for beautiful code highlighting
9+- **Interactive Playground**: Try tylex in the browser (coming soon)
10+11+## Development
12+13+```sh
14+pnpm install
15+pnpm run dev
16+```
17+18+## Building
19+20+The build process automatically:
21+1. Compiles TypeSpec examples **in memory** during the Astro build
22+2. Reads TypeSpec source files
23+3. Syntax-highlights and displays them side-by-side with generated JSON
24+25+```sh
26+pnpm run build
27+```
28+29+No intermediate files are generated - everything happens in memory!
30+31+## Adding Examples
32+33+1. Create a new `.tsp` file in `src/examples/`
34+2. Add it to the examples array in `src/pages/index.astro`
35+3. Run `pnpm run build` to see it on the site
36+37+## Commands
38+39+| Command | Action |
40+| :------------------------ | :----------------------------------------------- |
41+| `pnpm install` | Installs dependencies |
42+| `pnpm dev` | Starts local dev server at `localhost:4321` |
43+| `pnpm build` | Build your production site to `./dist/` |
44+| `pnpm preview` | Preview your build locally, before deploying |
45+46+## Structure
47+48+```
49+/
50+├── src/
51+│ ├── examples/ # TypeSpec examples
52+│ │ ├── profile.tsp
53+│ │ ├── getQuotes.tsp
54+│ │ └── ...
55+│ ├── pages/
56+│ │ └── index.astro # Landing page
57+│ ├── components/
58+│ │ └── Playground.tsx
59+│ └── utils/
60+│ └── compile.ts # In-memory TypeSpec compiler
61+└── package.json
62+```
+11
packages/website/astro.config.mjs
···00000000000
···1+// @ts-check
2+import { defineConfig } from 'astro/config';
3+import react from '@astrojs/react';
4+5+// https://astro.build/config
6+export default defineConfig({
7+ integrations: [react()],
8+ vite: {
9+ // Vite config accessible for future playground tweaks
10+ }
11+});