diff --git a/experimental/atmii/.gitignore b/experimental/atmii/.gitignore
index 5bb30a7..6475fa6 100644
--- a/experimental/atmii/.gitignore
+++ b/experimental/atmii/.gitignore
@@ -46,3 +46,39 @@ lerna-debug.log*
# Database
*.sqlite
*.sqlite-journal
+
+# Parcel
+.cache/
+.idea/
+.nyc_output/
+.parcel-cache/
+.verdaccio_storage/
+.vscode/*
+!.vscode/extensions.json
+coverage/
+dist/
+lib/
+logs/
+node_modules/
+parcel-bundle-reports/
+tmp
+
+/target/
+
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/sdks
+!.yarn/versions
+
+.DS_Store
+npm-debug.log*
+package-lock.json
+sourcemap-info.json
+yarn-debug.log*
+yarn-error.log*
+*.log
+*.min.js
+*.node
\ No newline at end of file
diff --git a/experimental/atmii/lexicons/app/bsky/actor/defs.json b/experimental/atmii/lexicons/app/bsky/actor/defs.json
new file mode 100644
index 0000000..b2ce1f5
--- /dev/null
+++ b/experimental/atmii/lexicons/app/bsky/actor/defs.json
@@ -0,0 +1,31 @@
+{
+ "lexicon": 1,
+ "id": "app.bsky.actor.defs",
+ "defs": {
+ "profileView": {
+ "type": "object",
+ "required": ["did", "handle"],
+ "properties": {
+ "did": { "type": "string", "format": "did" },
+ "handle": { "type": "string", "format": "handle" },
+ "displayName": {
+ "type": "string",
+ "maxGraphemes": 64,
+ "maxLength": 640
+ },
+ "description": {
+ "type": "string",
+ "maxGraphemes": 256,
+ "maxLength": 2560
+ },
+ "avatar": { "type": "string", "format": "uri" },
+ "indexedAt": { "type": "string", "format": "datetime" },
+ "createdAt": { "type": "string", "format": "datetime" },
+ "labels": {
+ "type": "array",
+ "items": { "type": "ref", "ref": "com.atproto.label.defs#label" }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/app/bsky/actor/profile.json b/experimental/atmii/lexicons/app/bsky/actor/profile.json
new file mode 100644
index 0000000..911d7a0
--- /dev/null
+++ b/experimental/atmii/lexicons/app/bsky/actor/profile.json
@@ -0,0 +1,53 @@
+{
+ "lexicon": 1,
+ "id": "app.bsky.actor.profile",
+ "defs": {
+ "main": {
+ "type": "record",
+ "description": "A declaration of a Bluesky account profile.",
+ "key": "literal:self",
+ "record": {
+ "type": "object",
+ "properties": {
+ "displayName": {
+ "type": "string",
+ "maxGraphemes": 64,
+ "maxLength": 640
+ },
+ "description": {
+ "type": "string",
+ "description": "Free-form profile description text.",
+ "maxGraphemes": 256,
+ "maxLength": 2560
+ },
+ "avatar": {
+ "type": "blob",
+ "description": "Small image to be displayed next to posts from account. AKA, 'profile picture'",
+ "accept": ["image/png", "image/jpeg"],
+ "maxSize": 1000000
+ },
+ "banner": {
+ "type": "blob",
+ "description": "Larger horizontal image to display behind profile view.",
+ "accept": ["image/png", "image/jpeg"],
+ "maxSize": 1000000
+ },
+ "labels": {
+ "type": "union",
+ "description": "Self-label values, specific to the Bluesky application, on the overall account.",
+ "refs": ["com.atproto.label.defs#selfLabels"]
+ },
+ "joinedViaStarterPack": {
+ "type": "ref",
+ "ref": "com.atproto.repo.strongRef"
+ },
+ "pinnedPost": {
+ "type": "ref",
+ "ref": "com.atproto.repo.strongRef"
+ },
+ "createdAt": { "type": "string", "format": "datetime" }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/label/defs.json b/experimental/atmii/lexicons/com/atproto/label/defs.json
new file mode 100644
index 0000000..6f4c1ab
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/label/defs.json
@@ -0,0 +1,156 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.label.defs",
+ "defs": {
+ "label": {
+ "type": "object",
+ "description": "Metadata tag on an atproto resource (eg, repo or record).",
+ "required": ["src", "uri", "val", "cts"],
+ "properties": {
+ "ver": {
+ "type": "integer",
+ "description": "The AT Protocol version of the label object."
+ },
+ "src": {
+ "type": "string",
+ "format": "did",
+ "description": "DID of the actor who created this label."
+ },
+ "uri": {
+ "type": "string",
+ "format": "uri",
+ "description": "AT URI of the record, repository (account), or other resource that this label applies to."
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "Optionally, CID specifying the specific version of 'uri' resource this label applies to."
+ },
+ "val": {
+ "type": "string",
+ "maxLength": 128,
+ "description": "The short string name of the value or type of this label."
+ },
+ "neg": {
+ "type": "boolean",
+ "description": "If true, this is a negation label, overwriting a previous label."
+ },
+ "cts": {
+ "type": "string",
+ "format": "datetime",
+ "description": "Timestamp when this label was created."
+ },
+ "exp": {
+ "type": "string",
+ "format": "datetime",
+ "description": "Timestamp at which this label expires (no longer applies)."
+ },
+ "sig": {
+ "type": "bytes",
+ "description": "Signature of dag-cbor encoded label."
+ }
+ }
+ },
+ "selfLabels": {
+ "type": "object",
+ "description": "Metadata tags on an atproto record, published by the author within the record.",
+ "required": ["values"],
+ "properties": {
+ "values": {
+ "type": "array",
+ "items": { "type": "ref", "ref": "#selfLabel" },
+ "maxLength": 10
+ }
+ }
+ },
+ "selfLabel": {
+ "type": "object",
+ "description": "Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.",
+ "required": ["val"],
+ "properties": {
+ "val": {
+ "type": "string",
+ "maxLength": 128,
+ "description": "The short string name of the value or type of this label."
+ }
+ }
+ },
+ "labelValueDefinition": {
+ "type": "object",
+ "description": "Declares a label value and its expected interpretations and behaviors.",
+ "required": ["identifier", "severity", "blurs", "locales"],
+ "properties": {
+ "identifier": {
+ "type": "string",
+ "description": "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).",
+ "maxLength": 100,
+ "maxGraphemes": 100
+ },
+ "severity": {
+ "type": "string",
+ "description": "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.",
+ "knownValues": ["inform", "alert", "none"]
+ },
+ "blurs": {
+ "type": "string",
+ "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.",
+ "knownValues": ["content", "media", "none"]
+ },
+ "defaultSetting": {
+ "type": "string",
+ "description": "The default setting for this label.",
+ "knownValues": ["ignore", "warn", "hide"],
+ "default": "warn"
+ },
+ "adultOnly": {
+ "type": "boolean",
+ "description": "Does the user need to have adult content enabled in order to configure this label?"
+ },
+ "locales": {
+ "type": "array",
+ "items": { "type": "ref", "ref": "#labelValueDefinitionStrings" }
+ }
+ }
+ },
+ "labelValueDefinitionStrings": {
+ "type": "object",
+ "description": "Strings which describe the label in the UI, localized into a specific language.",
+ "required": ["lang", "name", "description"],
+ "properties": {
+ "lang": {
+ "type": "string",
+ "description": "The code of the language these strings are written in.",
+ "format": "language"
+ },
+ "name": {
+ "type": "string",
+ "description": "A short human-readable name for the label.",
+ "maxGraphemes": 64,
+ "maxLength": 640
+ },
+ "description": {
+ "type": "string",
+ "description": "A longer description of what the label means and why it might be applied.",
+ "maxGraphemes": 10000,
+ "maxLength": 100000
+ }
+ }
+ },
+ "labelValue": {
+ "type": "string",
+ "knownValues": [
+ "!hide",
+ "!no-promote",
+ "!warn",
+ "!no-unauthenticated",
+ "dmca-violation",
+ "doxxing",
+ "porn",
+ "sexual",
+ "nudity",
+ "nsfl",
+ "gore"
+ ]
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/applyWrites.json b/experimental/atmii/lexicons/com/atproto/repo/applyWrites.json
new file mode 100644
index 0000000..11a1f1f
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/applyWrites.json
@@ -0,0 +1,131 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.applyWrites",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["repo", "writes"],
+ "properties": {
+ "repo": {
+ "type": "string",
+ "format": "at-identifier",
+ "description": "The handle or DID of the repo (aka, current account)."
+ },
+ "validate": {
+ "type": "boolean",
+ "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."
+ },
+ "writes": {
+ "type": "array",
+ "items": {
+ "type": "union",
+ "refs": ["#create", "#update", "#delete"],
+ "closed": true
+ }
+ },
+ "swapCommit": {
+ "type": "string",
+ "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.",
+ "format": "cid"
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": [],
+ "properties": {
+ "commit": {
+ "type": "ref",
+ "ref": "com.atproto.repo.defs#commitMeta"
+ },
+ "results": {
+ "type": "array",
+ "items": {
+ "type": "union",
+ "refs": ["#createResult", "#updateResult", "#deleteResult"],
+ "closed": true
+ }
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "InvalidSwap",
+ "description": "Indicates that the 'swapCommit' parameter did not match current commit."
+ }
+ ]
+ },
+ "create": {
+ "type": "object",
+ "description": "Operation which creates a new record.",
+ "required": ["collection", "value"],
+ "properties": {
+ "collection": { "type": "string", "format": "nsid" },
+ "rkey": {
+ "type": "string",
+ "maxLength": 512,
+ "format": "record-key",
+ "description": "NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility."
+ },
+ "value": { "type": "unknown" }
+ }
+ },
+ "update": {
+ "type": "object",
+ "description": "Operation which updates an existing record.",
+ "required": ["collection", "rkey", "value"],
+ "properties": {
+ "collection": { "type": "string", "format": "nsid" },
+ "rkey": { "type": "string", "format": "record-key" },
+ "value": { "type": "unknown" }
+ }
+ },
+ "delete": {
+ "type": "object",
+ "description": "Operation which deletes an existing record.",
+ "required": ["collection", "rkey"],
+ "properties": {
+ "collection": { "type": "string", "format": "nsid" },
+ "rkey": { "type": "string", "format": "record-key" }
+ }
+ },
+ "createResult": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "cid": { "type": "string", "format": "cid" },
+ "validationStatus": {
+ "type": "string",
+ "knownValues": ["valid", "unknown"]
+ }
+ }
+ },
+ "updateResult": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "cid": { "type": "string", "format": "cid" },
+ "validationStatus": {
+ "type": "string",
+ "knownValues": ["valid", "unknown"]
+ }
+ }
+ },
+ "deleteResult": {
+ "type": "object",
+ "required": [],
+ "properties": {}
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/createRecord.json b/experimental/atmii/lexicons/com/atproto/repo/createRecord.json
new file mode 100644
index 0000000..de5f408
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/createRecord.json
@@ -0,0 +1,73 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.createRecord",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Create a single new repository record. Requires auth, implemented by PDS.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["repo", "collection", "record"],
+ "properties": {
+ "repo": {
+ "type": "string",
+ "format": "at-identifier",
+ "description": "The handle or DID of the repo (aka, current account)."
+ },
+ "collection": {
+ "type": "string",
+ "format": "nsid",
+ "description": "The NSID of the record collection."
+ },
+ "rkey": {
+ "type": "string",
+ "format": "record-key",
+ "description": "The Record Key.",
+ "maxLength": 512
+ },
+ "validate": {
+ "type": "boolean",
+ "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."
+ },
+ "record": {
+ "type": "unknown",
+ "description": "The record itself. Must contain a $type field."
+ },
+ "swapCommit": {
+ "type": "string",
+ "format": "cid",
+ "description": "Compare and swap with the previous commit by CID."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "cid": { "type": "string", "format": "cid" },
+ "commit": {
+ "type": "ref",
+ "ref": "com.atproto.repo.defs#commitMeta"
+ },
+ "validationStatus": {
+ "type": "string",
+ "knownValues": ["valid", "unknown"]
+ }
+ }
+ }
+ },
+ "errors": [
+ {
+ "name": "InvalidSwap",
+ "description": "Indicates that 'swapCommit' didn't match current repo commit."
+ }
+ ]
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/defs.json b/experimental/atmii/lexicons/com/atproto/repo/defs.json
new file mode 100644
index 0000000..8752599
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/defs.json
@@ -0,0 +1,14 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.defs",
+ "defs": {
+ "commitMeta": {
+ "type": "object",
+ "required": ["cid", "rev"],
+ "properties": {
+ "cid": { "type": "string", "format": "cid" },
+ "rev": { "type": "string", "format": "tid" }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/deleteRecord.json b/experimental/atmii/lexicons/com/atproto/repo/deleteRecord.json
new file mode 100644
index 0000000..9831da1
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/deleteRecord.json
@@ -0,0 +1,57 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.deleteRecord",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["repo", "collection", "rkey"],
+ "properties": {
+ "repo": {
+ "type": "string",
+ "format": "at-identifier",
+ "description": "The handle or DID of the repo (aka, current account)."
+ },
+ "collection": {
+ "type": "string",
+ "format": "nsid",
+ "description": "The NSID of the record collection."
+ },
+ "rkey": {
+ "type": "string",
+ "format": "record-key",
+ "description": "The Record Key."
+ },
+ "swapRecord": {
+ "type": "string",
+ "format": "cid",
+ "description": "Compare and swap with the previous record by CID."
+ },
+ "swapCommit": {
+ "type": "string",
+ "format": "cid",
+ "description": "Compare and swap with the previous commit by CID."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "commit": {
+ "type": "ref",
+ "ref": "com.atproto.repo.defs#commitMeta"
+ }
+ }
+ }
+ },
+ "errors": [{ "name": "InvalidSwap" }]
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/describeRepo.json b/experimental/atmii/lexicons/com/atproto/repo/describeRepo.json
new file mode 100644
index 0000000..b1ce2b6
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/describeRepo.json
@@ -0,0 +1,51 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.describeRepo",
+ "defs": {
+ "main": {
+ "type": "query",
+ "description": "Get information about an account and repository, including the list of collections. Does not require auth.",
+ "parameters": {
+ "type": "params",
+ "required": ["repo"],
+ "properties": {
+ "repo": {
+ "type": "string",
+ "format": "at-identifier",
+ "description": "The handle or DID of the repo."
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": [
+ "handle",
+ "did",
+ "didDoc",
+ "collections",
+ "handleIsCorrect"
+ ],
+ "properties": {
+ "handle": { "type": "string", "format": "handle" },
+ "did": { "type": "string", "format": "did" },
+ "didDoc": {
+ "type": "unknown",
+ "description": "The complete DID document for this account."
+ },
+ "collections": {
+ "type": "array",
+ "description": "List of all the collections (NSIDs) for which this repo contains at least one record.",
+ "items": { "type": "string", "format": "nsid" }
+ },
+ "handleIsCorrect": {
+ "type": "boolean",
+ "description": "Indicates if handle is currently valid (resolves bi-directionally)"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/getRecord.json b/experimental/atmii/lexicons/com/atproto/repo/getRecord.json
new file mode 100644
index 0000000..388b9c5
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/getRecord.json
@@ -0,0 +1,49 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.getRecord",
+ "defs": {
+ "main": {
+ "type": "query",
+ "description": "Get a single record from a repository. Does not require auth.",
+ "parameters": {
+ "type": "params",
+ "required": ["repo", "collection", "rkey"],
+ "properties": {
+ "repo": {
+ "type": "string",
+ "format": "at-identifier",
+ "description": "The handle or DID of the repo."
+ },
+ "collection": {
+ "type": "string",
+ "format": "nsid",
+ "description": "The NSID of the record collection."
+ },
+ "rkey": {
+ "type": "string",
+ "description": "The Record Key.",
+ "format": "record-key"
+ },
+ "cid": {
+ "type": "string",
+ "format": "cid",
+ "description": "The CID of the version of the record. If not specified, then return the most recent version."
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "value"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "cid": { "type": "string", "format": "cid" },
+ "value": { "type": "unknown" }
+ }
+ }
+ },
+ "errors": [{ "name": "RecordNotFound" }]
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/importRepo.json b/experimental/atmii/lexicons/com/atproto/repo/importRepo.json
new file mode 100644
index 0000000..fc850b1
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/importRepo.json
@@ -0,0 +1,13 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.importRepo",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.",
+ "input": {
+ "encoding": "application/vnd.ipld.car"
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/listMissingBlobs.json b/experimental/atmii/lexicons/com/atproto/repo/listMissingBlobs.json
new file mode 100644
index 0000000..c39913d
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/listMissingBlobs.json
@@ -0,0 +1,44 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.listMissingBlobs",
+ "defs": {
+ "main": {
+ "type": "query",
+ "description": "Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.",
+ "parameters": {
+ "type": "params",
+ "properties": {
+ "limit": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 1000,
+ "default": 500
+ },
+ "cursor": { "type": "string" }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["blobs"],
+ "properties": {
+ "cursor": { "type": "string" },
+ "blobs": {
+ "type": "array",
+ "items": { "type": "ref", "ref": "#recordBlob" }
+ }
+ }
+ }
+ }
+ },
+ "recordBlob": {
+ "type": "object",
+ "required": ["cid", "recordUri"],
+ "properties": {
+ "cid": { "type": "string", "format": "cid" },
+ "recordUri": { "type": "string", "format": "at-uri" }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/listRecords.json b/experimental/atmii/lexicons/com/atproto/repo/listRecords.json
new file mode 100644
index 0000000..bc91c95
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/listRecords.json
@@ -0,0 +1,69 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.listRecords",
+ "defs": {
+ "main": {
+ "type": "query",
+ "description": "List a range of records in a repository, matching a specific collection. Does not require auth.",
+ "parameters": {
+ "type": "params",
+ "required": ["repo", "collection"],
+ "properties": {
+ "repo": {
+ "type": "string",
+ "format": "at-identifier",
+ "description": "The handle or DID of the repo."
+ },
+ "collection": {
+ "type": "string",
+ "format": "nsid",
+ "description": "The NSID of the record type."
+ },
+ "limit": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 100,
+ "default": 50,
+ "description": "The number of records to return."
+ },
+ "cursor": { "type": "string" },
+ "rkeyStart": {
+ "type": "string",
+ "description": "DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)"
+ },
+ "rkeyEnd": {
+ "type": "string",
+ "description": "DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)"
+ },
+ "reverse": {
+ "type": "boolean",
+ "description": "Flag to reverse the order of the returned records."
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["records"],
+ "properties": {
+ "cursor": { "type": "string" },
+ "records": {
+ "type": "array",
+ "items": { "type": "ref", "ref": "#record" }
+ }
+ }
+ }
+ }
+ },
+ "record": {
+ "type": "object",
+ "required": ["uri", "cid", "value"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "cid": { "type": "string", "format": "cid" },
+ "value": { "type": "unknown" }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/putRecord.json b/experimental/atmii/lexicons/com/atproto/repo/putRecord.json
new file mode 100644
index 0000000..830fade
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/putRecord.json
@@ -0,0 +1,74 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.putRecord",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["repo", "collection", "rkey", "record"],
+ "nullable": ["swapRecord"],
+ "properties": {
+ "repo": {
+ "type": "string",
+ "format": "at-identifier",
+ "description": "The handle or DID of the repo (aka, current account)."
+ },
+ "collection": {
+ "type": "string",
+ "format": "nsid",
+ "description": "The NSID of the record collection."
+ },
+ "rkey": {
+ "type": "string",
+ "format": "record-key",
+ "description": "The Record Key.",
+ "maxLength": 512
+ },
+ "validate": {
+ "type": "boolean",
+ "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."
+ },
+ "record": {
+ "type": "unknown",
+ "description": "The record to write."
+ },
+ "swapRecord": {
+ "type": "string",
+ "format": "cid",
+ "description": "Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation"
+ },
+ "swapCommit": {
+ "type": "string",
+ "format": "cid",
+ "description": "Compare and swap with the previous commit by CID."
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "cid": { "type": "string", "format": "cid" },
+ "commit": {
+ "type": "ref",
+ "ref": "com.atproto.repo.defs#commitMeta"
+ },
+ "validationStatus": {
+ "type": "string",
+ "knownValues": ["valid", "unknown"]
+ }
+ }
+ }
+ },
+ "errors": [{ "name": "InvalidSwap" }]
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/strongRef.json b/experimental/atmii/lexicons/com/atproto/repo/strongRef.json
new file mode 100644
index 0000000..cb79625
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/strongRef.json
@@ -0,0 +1,15 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.strongRef",
+ "description": "A URI with a content-hash fingerprint.",
+ "defs": {
+ "main": {
+ "type": "object",
+ "required": ["uri", "cid"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "cid": { "type": "string", "format": "cid" }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/com/atproto/repo/uploadBlob.json b/experimental/atmii/lexicons/com/atproto/repo/uploadBlob.json
new file mode 100644
index 0000000..547a995
--- /dev/null
+++ b/experimental/atmii/lexicons/com/atproto/repo/uploadBlob.json
@@ -0,0 +1,23 @@
+{
+ "lexicon": 1,
+ "id": "com.atproto.repo.uploadBlob",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "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.",
+ "input": {
+ "encoding": "*/*"
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["blob"],
+ "properties": {
+ "blob": { "type": "blob" }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/xyz/statusphere/defs.json b/experimental/atmii/lexicons/xyz/statusphere/defs.json
new file mode 100644
index 0000000..90c4488
--- /dev/null
+++ b/experimental/atmii/lexicons/xyz/statusphere/defs.json
@@ -0,0 +1,29 @@
+{
+ "lexicon": 1,
+ "id": "xyz.statusphere.defs",
+ "defs": {
+ "statusView": {
+ "type": "object",
+ "required": ["uri", "status", "profile", "createdAt"],
+ "properties": {
+ "uri": { "type": "string", "format": "at-uri" },
+ "status": {
+ "type": "string",
+ "minLength": 1,
+ "maxGraphemes": 1,
+ "maxLength": 32
+ },
+ "createdAt": { "type": "string", "format": "datetime" },
+ "profile": { "type": "ref", "ref": "#profileView" }
+ }
+ },
+ "profileView": {
+ "type": "object",
+ "required": ["did", "handle"],
+ "properties": {
+ "did": { "type": "string", "format": "did" },
+ "handle": { "type": "string", "format": "handle" }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/xyz/statusphere/getStatuses.json b/experimental/atmii/lexicons/xyz/statusphere/getStatuses.json
new file mode 100644
index 0000000..156515a
--- /dev/null
+++ b/experimental/atmii/lexicons/xyz/statusphere/getStatuses.json
@@ -0,0 +1,37 @@
+{
+ "lexicon": 1,
+ "id": "xyz.statusphere.getStatuses",
+ "defs": {
+ "main": {
+ "type": "query",
+ "description": "Get a list of the most recent statuses on the network.",
+ "parameters": {
+ "type": "params",
+ "properties": {
+ "limit": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 100,
+ "default": 50
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["statuses"],
+ "properties": {
+ "statuses": {
+ "type": "array",
+ "items": {
+ "type": "ref",
+ "ref": "xyz.statusphere.defs#statusView"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/xyz/statusphere/getUser.json b/experimental/atmii/lexicons/xyz/statusphere/getUser.json
new file mode 100644
index 0000000..c26bb7b
--- /dev/null
+++ b/experimental/atmii/lexicons/xyz/statusphere/getUser.json
@@ -0,0 +1,31 @@
+{
+ "lexicon": 1,
+ "id": "xyz.statusphere.getUser",
+ "defs": {
+ "main": {
+ "type": "query",
+ "description": "Get the current user's profile and status.",
+ "parameters": {
+ "type": "params",
+ "properties": {}
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["profile"],
+ "properties": {
+ "profile": {
+ "type": "ref",
+ "ref": "app.bsky.actor.defs#profileView"
+ },
+ "status": {
+ "type": "ref",
+ "ref": "xyz.statusphere.defs#statusView"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/xyz/statusphere/sendStatus.json b/experimental/atmii/lexicons/xyz/statusphere/sendStatus.json
new file mode 100644
index 0000000..c13556f
--- /dev/null
+++ b/experimental/atmii/lexicons/xyz/statusphere/sendStatus.json
@@ -0,0 +1,38 @@
+{
+ "lexicon": 1,
+ "id": "xyz.statusphere.sendStatus",
+ "defs": {
+ "main": {
+ "type": "procedure",
+ "description": "Send a status into the ATmosphere.",
+ "input": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["status"],
+ "properties": {
+ "status": {
+ "type": "string",
+ "minLength": 1,
+ "maxGraphemes": 1,
+ "maxLength": 32
+ }
+ }
+ }
+ },
+ "output": {
+ "encoding": "application/json",
+ "schema": {
+ "type": "object",
+ "required": ["status"],
+ "properties": {
+ "status": {
+ "type": "ref",
+ "ref": "xyz.statusphere.defs#statusView"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/lexicons/xyz/statusphere/status.json b/experimental/atmii/lexicons/xyz/statusphere/status.json
new file mode 100644
index 0000000..e4bf5a9
--- /dev/null
+++ b/experimental/atmii/lexicons/xyz/statusphere/status.json
@@ -0,0 +1,23 @@
+{
+ "lexicon": 1,
+ "id": "xyz.statusphere.status",
+ "defs": {
+ "main": {
+ "type": "record",
+ "key": "tid",
+ "record": {
+ "type": "object",
+ "required": ["status", "createdAt"],
+ "properties": {
+ "status": {
+ "type": "string",
+ "minLength": 1,
+ "maxGraphemes": 1,
+ "maxLength": 32
+ },
+ "createdAt": { "type": "string", "format": "datetime" }
+ }
+ }
+ }
+ }
+}
diff --git a/experimental/atmii/packages/client/package.json b/experimental/atmii/packages/client/package.json
index d74cf1e..a5de759 100644
--- a/experimental/atmii/packages/client/package.json
+++ b/experimental/atmii/packages/client/package.json
@@ -21,7 +21,7 @@
"iron-session": "^8.0.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
- "react-router-dom": "^7.2.0"
+ "react-router": "^7.2.0"
},
"devDependencies": {
"@types/react": "^19.0.10",
diff --git a/experimental/atmii/packages/client/src/App.tsx b/experimental/atmii/packages/client/src/App.tsx
index a5804d6..88f5bd5 100644
--- a/experimental/atmii/packages/client/src/App.tsx
+++ b/experimental/atmii/packages/client/src/App.tsx
@@ -1,10 +1,10 @@
-import { Route, Routes } from 'react-router-dom'
+import { Route, Routes } from 'react-router'
-import { AuthProvider } from '#/hooks/useAuth'
-import HomePage from '#/pages/HomePage'
-import LoginPage from '#/pages/LoginPage'
-import OAuthCallbackPage from '#/pages/OAuthCallbackPage'
-import Channel from '#/pages/Channel'
+import { AuthProvider } from 'client-src/hooks/useAuth'
+//import HomePage from '#/pages/HomePage'
+//import LoginPage from '#/pages/LoginPage'
+//import OAuthCallbackPage from '#/pages/OAuthCallbackPage'
+//import Channel from '#/pages/Channel'
function App() {
return (
@@ -12,10 +12,12 @@ function App() {
+ {/*
} />
} />
} />
} />
+ */}
diff --git a/experimental/atmii/packages/client/src/hooks/useAuth.tsx b/experimental/atmii/packages/client/src/hooks/useAuth.tsx
new file mode 100644
index 0000000..7f62a20
--- /dev/null
+++ b/experimental/atmii/packages/client/src/hooks/useAuth.tsx
@@ -0,0 +1,138 @@
+import { createContext, ReactNode, useContext, useState } from 'react'
+import { useQuery, useQueryClient } from '@tanstack/react-query'
+import { XRPCError } from '@atproto/xrpc'
+import { XyzStatusphereGetUser } from '@atmii/lexicon'
+
+import api from 'client-src/services/api'
+
+interface AuthContextType {
+ user: XyzStatusphereGetUser.OutputSchema | null
+ loading: boolean
+ error: string | null
+ login: (handle: string) => Promise<{ redirectUrl: string }>
+ logout: () => Promise
+}
+
+const AuthContext = createContext(undefined)
+
+export function AuthProvider({ children }: { children: ReactNode }) {
+ const [error, setError] = useState(null)
+ const queryClient = useQueryClient()
+
+ // Use React Query to fetch and manage user data
+ const {
+ data: user,
+ isLoading: loading,
+ error: queryError,
+ } = useQuery({
+ queryKey: ['currentUser'],
+ queryFn: async () => {
+ // Check for error parameter in URL (from OAuth redirect)
+ const urlParams = new URLSearchParams(window.location.search)
+ const errorParam = urlParams.get('error')
+
+ if (errorParam) {
+ setError('Authentication failed. Please try again.')
+
+ // Remove the error parameter from the URL
+ const newUrl = window.location.pathname
+ window.history.replaceState({}, document.title, newUrl)
+ return null
+ }
+
+ try {
+ const { data: userData } = await api.getCurrentUser({})
+
+ // Clean up URL if needed
+ if (window.location.search && userData) {
+ window.history.replaceState(
+ {},
+ document.title,
+ window.location.pathname,
+ )
+ }
+
+ return userData
+ } catch (apiErr) {
+ if (
+ apiErr instanceof XRPCError &&
+ apiErr.error === 'AuthenticationRequired'
+ ) {
+ return null
+ }
+
+ console.error('🚫 API error during auth check:', apiErr)
+
+ // If it's a network error, provide a more helpful message
+ if (
+ apiErr instanceof TypeError &&
+ apiErr.message.includes('Failed to fetch')
+ ) {
+ throw new Error(
+ 'Cannot connect to API server. Please check your network connection or server status.',
+ )
+ }
+
+ throw apiErr
+ }
+ },
+ retry: false,
+ staleTime: 5 * 60 * 1000, // 5 minutes
+ })
+
+ const login = async (handle: string) => {
+ setError(null)
+
+ try {
+ return await api.login(handle)
+ } catch (err) {
+ const message = err instanceof Error ? err.message : 'Login failed'
+ setError(message)
+ throw err
+ }
+ }
+
+ const logout = async () => {
+ try {
+ await api.logout()
+ // Reset the user data in React Query cache
+ queryClient.setQueryData(['currentUser'], null)
+ // Invalidate any user-dependent queries
+ queryClient.invalidateQueries({ queryKey: ['statuses'] })
+ } catch (err) {
+ const message = err instanceof Error ? err.message : 'Logout failed'
+ setError(message)
+ throw err
+ }
+ }
+
+ // Combine state error with query error
+ const combinedError =
+ error || (queryError instanceof Error ? queryError.message : null)
+
+ return (
+
+ {children}
+
+ )
+}
+
+export function useAuth() {
+ const context = useContext(AuthContext)
+
+ if (context === undefined) {
+ throw new Error('useAuth must be used within an AuthProvider')
+ }
+
+ return context
+}
+
+export default useAuth
diff --git a/experimental/atmii/packages/client/src/main.tsx b/experimental/atmii/packages/client/src/main.tsx
index eb786e2..0edb035 100644
--- a/experimental/atmii/packages/client/src/main.tsx
+++ b/experimental/atmii/packages/client/src/main.tsx
@@ -1,11 +1,11 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
-import { BrowserRouter } from 'react-router-dom'
+import { BrowserRouter } from 'react-router'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
-import App from '#/App'
+import App from 'client-src/App'
-import '#/index.css'
+//import 'client-src/index.css'
const queryClient = new QueryClient()
diff --git a/experimental/atmii/packages/client/src/services/api.ts b/experimental/atmii/packages/client/src/services/api.ts
new file mode 100644
index 0000000..caa92a1
--- /dev/null
+++ b/experimental/atmii/packages/client/src/services/api.ts
@@ -0,0 +1,80 @@
+import * as Lexicon from '@atmii/lexicon'
+import type {
+ XyzStatusphereGetStatuses,
+ XyzStatusphereGetUser,
+ XyzStatusphereSendStatus,
+} from '@atmii/lexicon'
+
+class StatusphereAgent extends Lexicon.AtpBaseClient {
+ constructor() {
+ super(StatusphereAgent.fetchHandler)
+ }
+
+ private static fetchHandler: Lexicon.AtpBaseClient['fetchHandler'] = (
+ path,
+ options,
+ ) => {
+ return fetch(path, {
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ credentials: 'include',
+ })
+ }
+}
+
+const agent = new StatusphereAgent()
+
+// API service
+export const api = {
+ // Login
+ async login(handle: string) {
+ const response = await fetch('/oauth/initiate', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ credentials: 'include',
+ body: JSON.stringify({ handle }),
+ })
+
+ if (!response.ok) {
+ const error = await response.json()
+ throw new Error(error.error || 'Login failed')
+ }
+
+ return response.json()
+ },
+
+ // Logout
+ async logout() {
+ const response = await fetch('/oauth/logout', {
+ method: 'POST',
+ credentials: 'include',
+ })
+
+ if (!response.ok) {
+ throw new Error('Logout failed')
+ }
+
+ return response.json()
+ },
+
+ // Get current user
+ getCurrentUser(params: XyzStatusphereGetUser.QueryParams) {
+ return agent.xyz.statusphere.getUser(params)
+ },
+
+ // Get statuses
+ getStatuses(params: XyzStatusphereGetStatuses.QueryParams) {
+ return agent.xyz.statusphere.getStatuses(params)
+ },
+
+ // Create status
+ createStatus(params: XyzStatusphereSendStatus.InputSchema) {
+ return agent.xyz.statusphere.sendStatus(params)
+ },
+}
+
+export default api
diff --git a/experimental/atmii/packages/client/tsconfig.json b/experimental/atmii/packages/client/tsconfig.json
index 8643591..c8b3cff 100644
--- a/experimental/atmii/packages/client/tsconfig.json
+++ b/experimental/atmii/packages/client/tsconfig.json
@@ -17,7 +17,7 @@
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
- "#/*": ["./src/*"]
+ "client-src/*": ["./src/*"]
}
},
"include": ["src"]
diff --git a/experimental/atmii/packages/lexicon/package.json b/experimental/atmii/packages/lexicon/package.json
index 5a9ff12..f337dd8 100644
--- a/experimental/atmii/packages/lexicon/package.json
+++ b/experimental/atmii/packages/lexicon/package.json
@@ -20,7 +20,7 @@
"dev": "tsup --watch",
"clean": "rimraf dist",
"typecheck": "tsc --noEmit",
- "lexgen": "lex gen-api ./src ../../lexicons/app/andref/*/* ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* --yes && pnpm format",
+ "lexgen": "lex gen-api ./src ../../lexicons/xyz/statusphere/* ../../lexicons/app/andref/*/* ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* --yes && pnpm format",
"format": "prettier --write src"
},
"dependencies": {
diff --git a/experimental/atmii/packages/lexicon/src/index.ts b/experimental/atmii/packages/lexicon/src/index.ts
index 1c17bc8..5600925 100644
--- a/experimental/atmii/packages/lexicon/src/index.ts
+++ b/experimental/atmii/packages/lexicon/src/index.ts
@@ -6,16 +6,60 @@ import { CID } from 'multiformats/cid'
import { schemas } from './lexicons.js'
import * as AppAndrefAtmiiMii from './types/app/andref/atmii/mii.js'
+import * as AppBskyActorDefs from './types/app/bsky/actor/defs.js'
+import * as AppBskyActorProfile from './types/app/bsky/actor/profile.js'
+import * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.js'
+import * as ComAtprotoRepoApplyWrites from './types/com/atproto/repo/applyWrites.js'
+import * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createRecord.js'
+import * as ComAtprotoRepoDefs from './types/com/atproto/repo/defs.js'
+import * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord.js'
+import * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo.js'
+import * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord.js'
+import * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo.js'
+import * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs.js'
+import * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords.js'
+import * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord.js'
+import * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.js'
+import * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob.js'
+import * as XyzStatusphereDefs from './types/xyz/statusphere/defs.js'
+import * as XyzStatusphereGetStatuses from './types/xyz/statusphere/getStatuses.js'
+import * as XyzStatusphereGetUser from './types/xyz/statusphere/getUser.js'
+import * as XyzStatusphereSendStatus from './types/xyz/statusphere/sendStatus.js'
+import * as XyzStatusphereStatus from './types/xyz/statusphere/status.js'
import { OmitKey, Un$Typed } from './util.js'
+export * as XyzStatusphereDefs from './types/xyz/statusphere/defs.js'
+export * as XyzStatusphereGetStatuses from './types/xyz/statusphere/getStatuses.js'
+export * as XyzStatusphereGetUser from './types/xyz/statusphere/getUser.js'
+export * as XyzStatusphereSendStatus from './types/xyz/statusphere/sendStatus.js'
+export * as XyzStatusphereStatus from './types/xyz/statusphere/status.js'
export * as AppAndrefAtmiiMii from './types/app/andref/atmii/mii.js'
+export * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.js'
+export * as ComAtprotoRepoApplyWrites from './types/com/atproto/repo/applyWrites.js'
+export * as ComAtprotoRepoCreateRecord from './types/com/atproto/repo/createRecord.js'
+export * as ComAtprotoRepoDefs from './types/com/atproto/repo/defs.js'
+export * as ComAtprotoRepoDeleteRecord from './types/com/atproto/repo/deleteRecord.js'
+export * as ComAtprotoRepoDescribeRepo from './types/com/atproto/repo/describeRepo.js'
+export * as ComAtprotoRepoGetRecord from './types/com/atproto/repo/getRecord.js'
+export * as ComAtprotoRepoImportRepo from './types/com/atproto/repo/importRepo.js'
+export * as ComAtprotoRepoListMissingBlobs from './types/com/atproto/repo/listMissingBlobs.js'
+export * as ComAtprotoRepoListRecords from './types/com/atproto/repo/listRecords.js'
+export * as ComAtprotoRepoPutRecord from './types/com/atproto/repo/putRecord.js'
+export * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.js'
+export * as ComAtprotoRepoUploadBlob from './types/com/atproto/repo/uploadBlob.js'
+export * as AppBskyActorDefs from './types/app/bsky/actor/defs.js'
+export * as AppBskyActorProfile from './types/app/bsky/actor/profile.js'
export class AtpBaseClient extends XrpcClient {
+ xyz: XyzNS
app: AppNS
+ com: ComNS
constructor(options: FetchHandler | FetchHandlerOptions) {
super(options, schemas)
+ this.xyz = new XyzNS(this)
this.app = new AppNS(this)
+ this.com = new ComNS(this)
}
/** @deprecated use `this` instead */
@@ -24,13 +68,122 @@ export class AtpBaseClient extends XrpcClient {
}
}
+export class XyzNS {
+ _client: XrpcClient
+ statusphere: XyzStatusphereNS
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ this.statusphere = new XyzStatusphereNS(client)
+ }
+}
+
+export class XyzStatusphereNS {
+ _client: XrpcClient
+ status: StatusRecord
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ this.status = new StatusRecord(client)
+ }
+
+ getStatuses(
+ params?: XyzStatusphereGetStatuses.QueryParams,
+ opts?: XyzStatusphereGetStatuses.CallOptions,
+ ): Promise {
+ return this._client.call(
+ 'xyz.statusphere.getStatuses',
+ params,
+ undefined,
+ opts,
+ )
+ }
+
+ getUser(
+ params?: XyzStatusphereGetUser.QueryParams,
+ opts?: XyzStatusphereGetUser.CallOptions,
+ ): Promise {
+ return this._client.call('xyz.statusphere.getUser', params, undefined, opts)
+ }
+
+ sendStatus(
+ data?: XyzStatusphereSendStatus.InputSchema,
+ opts?: XyzStatusphereSendStatus.CallOptions,
+ ): Promise {
+ return this._client.call('xyz.statusphere.sendStatus', opts?.qp, data, opts)
+ }
+}
+
+export class StatusRecord {
+ _client: XrpcClient
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ }
+
+ async list(
+ params: OmitKey,
+ ): Promise<{
+ cursor?: string
+ records: { uri: string; value: XyzStatusphereStatus.Record }[]
+ }> {
+ const res = await this._client.call('com.atproto.repo.listRecords', {
+ collection: 'xyz.statusphere.status',
+ ...params,
+ })
+ return res.data
+ }
+
+ async get(
+ params: OmitKey,
+ ): Promise<{ uri: string; cid: string; value: XyzStatusphereStatus.Record }> {
+ const res = await this._client.call('com.atproto.repo.getRecord', {
+ collection: 'xyz.statusphere.status',
+ ...params,
+ })
+ return res.data
+ }
+
+ async create(
+ params: OmitKey<
+ ComAtprotoRepoCreateRecord.InputSchema,
+ 'collection' | 'record'
+ >,
+ record: Un$Typed,
+ headers?: Record,
+ ): Promise<{ uri: string; cid: string }> {
+ const collection = 'xyz.statusphere.status'
+ const res = await this._client.call(
+ 'com.atproto.repo.createRecord',
+ undefined,
+ { collection, ...params, record: { ...record, $type: collection } },
+ { encoding: 'application/json', headers },
+ )
+ return res.data
+ }
+
+ async delete(
+ params: OmitKey,
+ headers?: Record,
+ ): Promise {
+ await this._client.call(
+ 'com.atproto.repo.deleteRecord',
+ undefined,
+ { collection: 'xyz.statusphere.status', ...params },
+ { headers },
+ )
+ }
+}
+
export class AppNS {
_client: XrpcClient
andref: AppAndrefNS
+ bsky: AppBskyNS
constructor(client: XrpcClient) {
this._client = client
this.andref = new AppAndrefNS(client)
+ this.bsky = new AppBskyNS(client)
}
}
@@ -114,3 +267,232 @@ export class MiiRecord {
)
}
}
+
+export class AppBskyNS {
+ _client: XrpcClient
+ actor: AppBskyActorNS
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ this.actor = new AppBskyActorNS(client)
+ }
+}
+
+export class AppBskyActorNS {
+ _client: XrpcClient
+ profile: ProfileRecord
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ this.profile = new ProfileRecord(client)
+ }
+}
+
+export class ProfileRecord {
+ _client: XrpcClient
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ }
+
+ async list(
+ params: OmitKey,
+ ): Promise<{
+ cursor?: string
+ records: { uri: string; value: AppBskyActorProfile.Record }[]
+ }> {
+ const res = await this._client.call('com.atproto.repo.listRecords', {
+ collection: 'app.bsky.actor.profile',
+ ...params,
+ })
+ return res.data
+ }
+
+ async get(
+ params: OmitKey,
+ ): Promise<{ uri: string; cid: string; value: AppBskyActorProfile.Record }> {
+ const res = await this._client.call('com.atproto.repo.getRecord', {
+ collection: 'app.bsky.actor.profile',
+ ...params,
+ })
+ return res.data
+ }
+
+ async create(
+ params: OmitKey<
+ ComAtprotoRepoCreateRecord.InputSchema,
+ 'collection' | 'record'
+ >,
+ record: Un$Typed,
+ headers?: Record,
+ ): Promise<{ uri: string; cid: string }> {
+ const collection = 'app.bsky.actor.profile'
+ const res = await this._client.call(
+ 'com.atproto.repo.createRecord',
+ undefined,
+ {
+ collection,
+ rkey: 'self',
+ ...params,
+ record: { ...record, $type: collection },
+ },
+ { encoding: 'application/json', headers },
+ )
+ return res.data
+ }
+
+ async delete(
+ params: OmitKey,
+ headers?: Record,
+ ): Promise {
+ await this._client.call(
+ 'com.atproto.repo.deleteRecord',
+ undefined,
+ { collection: 'app.bsky.actor.profile', ...params },
+ { headers },
+ )
+ }
+}
+
+export class ComNS {
+ _client: XrpcClient
+ atproto: ComAtprotoNS
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ this.atproto = new ComAtprotoNS(client)
+ }
+}
+
+export class ComAtprotoNS {
+ _client: XrpcClient
+ repo: ComAtprotoRepoNS
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ this.repo = new ComAtprotoRepoNS(client)
+ }
+}
+
+export class ComAtprotoRepoNS {
+ _client: XrpcClient
+
+ constructor(client: XrpcClient) {
+ this._client = client
+ }
+
+ applyWrites(
+ data?: ComAtprotoRepoApplyWrites.InputSchema,
+ opts?: ComAtprotoRepoApplyWrites.CallOptions,
+ ): Promise {
+ return this._client
+ .call('com.atproto.repo.applyWrites', opts?.qp, data, opts)
+ .catch((e) => {
+ throw ComAtprotoRepoApplyWrites.toKnownErr(e)
+ })
+ }
+
+ createRecord(
+ data?: ComAtprotoRepoCreateRecord.InputSchema,
+ opts?: ComAtprotoRepoCreateRecord.CallOptions,
+ ): Promise {
+ return this._client
+ .call('com.atproto.repo.createRecord', opts?.qp, data, opts)
+ .catch((e) => {
+ throw ComAtprotoRepoCreateRecord.toKnownErr(e)
+ })
+ }
+
+ deleteRecord(
+ data?: ComAtprotoRepoDeleteRecord.InputSchema,
+ opts?: ComAtprotoRepoDeleteRecord.CallOptions,
+ ): Promise {
+ return this._client
+ .call('com.atproto.repo.deleteRecord', opts?.qp, data, opts)
+ .catch((e) => {
+ throw ComAtprotoRepoDeleteRecord.toKnownErr(e)
+ })
+ }
+
+ describeRepo(
+ params?: ComAtprotoRepoDescribeRepo.QueryParams,
+ opts?: ComAtprotoRepoDescribeRepo.CallOptions,
+ ): Promise {
+ return this._client.call(
+ 'com.atproto.repo.describeRepo',
+ params,
+ undefined,
+ opts,
+ )
+ }
+
+ getRecord(
+ params?: ComAtprotoRepoGetRecord.QueryParams,
+ opts?: ComAtprotoRepoGetRecord.CallOptions,
+ ): Promise {
+ return this._client
+ .call('com.atproto.repo.getRecord', params, undefined, opts)
+ .catch((e) => {
+ throw ComAtprotoRepoGetRecord.toKnownErr(e)
+ })
+ }
+
+ importRepo(
+ data?: ComAtprotoRepoImportRepo.InputSchema,
+ opts?: ComAtprotoRepoImportRepo.CallOptions,
+ ): Promise {
+ return this._client.call(
+ 'com.atproto.repo.importRepo',
+ opts?.qp,
+ data,
+ opts,
+ )
+ }
+
+ listMissingBlobs(
+ params?: ComAtprotoRepoListMissingBlobs.QueryParams,
+ opts?: ComAtprotoRepoListMissingBlobs.CallOptions,
+ ): Promise {
+ return this._client.call(
+ 'com.atproto.repo.listMissingBlobs',
+ params,
+ undefined,
+ opts,
+ )
+ }
+
+ listRecords(
+ params?: ComAtprotoRepoListRecords.QueryParams,
+ opts?: ComAtprotoRepoListRecords.CallOptions,
+ ): Promise {
+ return this._client.call(
+ 'com.atproto.repo.listRecords',
+ params,
+ undefined,
+ opts,
+ )
+ }
+
+ putRecord(
+ data?: ComAtprotoRepoPutRecord.InputSchema,
+ opts?: ComAtprotoRepoPutRecord.CallOptions,
+ ): Promise {
+ return this._client
+ .call('com.atproto.repo.putRecord', opts?.qp, data, opts)
+ .catch((e) => {
+ throw ComAtprotoRepoPutRecord.toKnownErr(e)
+ })
+ }
+
+ uploadBlob(
+ data?: ComAtprotoRepoUploadBlob.InputSchema,
+ opts?: ComAtprotoRepoUploadBlob.CallOptions,
+ ): Promise {
+ return this._client.call(
+ 'com.atproto.repo.uploadBlob',
+ opts?.qp,
+ data,
+ opts,
+ )
+ }
+}
diff --git a/experimental/atmii/packages/lexicon/src/lexicons.ts b/experimental/atmii/packages/lexicon/src/lexicons.ts
index 7dcfed0..50f7563 100644
--- a/experimental/atmii/packages/lexicon/src/lexicons.ts
+++ b/experimental/atmii/packages/lexicon/src/lexicons.ts
@@ -11,6 +11,182 @@ import {
import { $Typed, is$typed, maybe$typed } from './util.js'
export const schemaDict = {
+ XyzStatusphereDefs: {
+ lexicon: 1,
+ id: 'xyz.statusphere.defs',
+ defs: {
+ statusView: {
+ type: 'object',
+ required: ['uri', 'status', 'profile', 'createdAt'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ status: {
+ type: 'string',
+ minLength: 1,
+ maxGraphemes: 1,
+ maxLength: 32,
+ },
+ createdAt: {
+ type: 'string',
+ format: 'datetime',
+ },
+ profile: {
+ type: 'ref',
+ ref: 'lex:xyz.statusphere.defs#profileView',
+ },
+ },
+ },
+ profileView: {
+ type: 'object',
+ required: ['did', 'handle'],
+ properties: {
+ did: {
+ type: 'string',
+ format: 'did',
+ },
+ handle: {
+ type: 'string',
+ format: 'handle',
+ },
+ },
+ },
+ },
+ },
+ XyzStatusphereGetStatuses: {
+ lexicon: 1,
+ id: 'xyz.statusphere.getStatuses',
+ defs: {
+ main: {
+ type: 'query',
+ description: 'Get a list of the most recent statuses on the network.',
+ parameters: {
+ type: 'params',
+ properties: {
+ limit: {
+ type: 'integer',
+ minimum: 1,
+ maximum: 100,
+ default: 50,
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['statuses'],
+ properties: {
+ statuses: {
+ type: 'array',
+ items: {
+ type: 'ref',
+ ref: 'lex:xyz.statusphere.defs#statusView',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ XyzStatusphereGetUser: {
+ lexicon: 1,
+ id: 'xyz.statusphere.getUser',
+ defs: {
+ main: {
+ type: 'query',
+ description: "Get the current user's profile and status.",
+ parameters: {
+ type: 'params',
+ properties: {},
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['profile'],
+ properties: {
+ profile: {
+ type: 'ref',
+ ref: 'lex:app.bsky.actor.defs#profileView',
+ },
+ status: {
+ type: 'ref',
+ ref: 'lex:xyz.statusphere.defs#statusView',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ XyzStatusphereSendStatus: {
+ lexicon: 1,
+ id: 'xyz.statusphere.sendStatus',
+ defs: {
+ main: {
+ type: 'procedure',
+ description: 'Send a status into the ATmosphere.',
+ input: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['status'],
+ properties: {
+ status: {
+ type: 'string',
+ minLength: 1,
+ maxGraphemes: 1,
+ maxLength: 32,
+ },
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['status'],
+ properties: {
+ status: {
+ type: 'ref',
+ ref: 'lex:xyz.statusphere.defs#statusView',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ XyzStatusphereStatus: {
+ lexicon: 1,
+ id: 'xyz.statusphere.status',
+ defs: {
+ main: {
+ type: 'record',
+ key: 'tid',
+ record: {
+ type: 'object',
+ required: ['status', 'createdAt'],
+ properties: {
+ status: {
+ type: 'string',
+ minLength: 1,
+ maxGraphemes: 1,
+ maxLength: 32,
+ },
+ createdAt: {
+ type: 'string',
+ format: 'datetime',
+ },
+ },
+ },
+ },
+ },
+ },
AppAndrefAtmiiMii: {
lexicon: 1,
id: 'app.andref.atmii.mii',
@@ -25,6 +201,1059 @@ export const schemaDict = {
},
},
},
+ ComAtprotoLabelDefs: {
+ lexicon: 1,
+ id: 'com.atproto.label.defs',
+ defs: {
+ label: {
+ type: 'object',
+ description:
+ 'Metadata tag on an atproto resource (eg, repo or record).',
+ required: ['src', 'uri', 'val', 'cts'],
+ properties: {
+ ver: {
+ type: 'integer',
+ description: 'The AT Protocol version of the label object.',
+ },
+ src: {
+ type: 'string',
+ format: 'did',
+ description: 'DID of the actor who created this label.',
+ },
+ uri: {
+ type: 'string',
+ format: 'uri',
+ description:
+ 'AT URI of the record, repository (account), or other resource that this label applies to.',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ description:
+ "Optionally, CID specifying the specific version of 'uri' resource this label applies to.",
+ },
+ val: {
+ type: 'string',
+ maxLength: 128,
+ description:
+ 'The short string name of the value or type of this label.',
+ },
+ neg: {
+ type: 'boolean',
+ description:
+ 'If true, this is a negation label, overwriting a previous label.',
+ },
+ cts: {
+ type: 'string',
+ format: 'datetime',
+ description: 'Timestamp when this label was created.',
+ },
+ exp: {
+ type: 'string',
+ format: 'datetime',
+ description:
+ 'Timestamp at which this label expires (no longer applies).',
+ },
+ sig: {
+ type: 'bytes',
+ description: 'Signature of dag-cbor encoded label.',
+ },
+ },
+ },
+ selfLabels: {
+ type: 'object',
+ description:
+ 'Metadata tags on an atproto record, published by the author within the record.',
+ required: ['values'],
+ properties: {
+ values: {
+ type: 'array',
+ items: {
+ type: 'ref',
+ ref: 'lex:com.atproto.label.defs#selfLabel',
+ },
+ maxLength: 10,
+ },
+ },
+ },
+ selfLabel: {
+ type: 'object',
+ description:
+ 'Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.',
+ required: ['val'],
+ properties: {
+ val: {
+ type: 'string',
+ maxLength: 128,
+ description:
+ 'The short string name of the value or type of this label.',
+ },
+ },
+ },
+ labelValueDefinition: {
+ type: 'object',
+ description:
+ 'Declares a label value and its expected interpretations and behaviors.',
+ required: ['identifier', 'severity', 'blurs', 'locales'],
+ properties: {
+ identifier: {
+ type: 'string',
+ description:
+ "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).",
+ maxLength: 100,
+ maxGraphemes: 100,
+ },
+ severity: {
+ type: 'string',
+ description:
+ "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.",
+ knownValues: ['inform', 'alert', 'none'],
+ },
+ blurs: {
+ type: 'string',
+ 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.",
+ knownValues: ['content', 'media', 'none'],
+ },
+ defaultSetting: {
+ type: 'string',
+ description: 'The default setting for this label.',
+ knownValues: ['ignore', 'warn', 'hide'],
+ default: 'warn',
+ },
+ adultOnly: {
+ type: 'boolean',
+ description:
+ 'Does the user need to have adult content enabled in order to configure this label?',
+ },
+ locales: {
+ type: 'array',
+ items: {
+ type: 'ref',
+ ref: 'lex:com.atproto.label.defs#labelValueDefinitionStrings',
+ },
+ },
+ },
+ },
+ labelValueDefinitionStrings: {
+ type: 'object',
+ description:
+ 'Strings which describe the label in the UI, localized into a specific language.',
+ required: ['lang', 'name', 'description'],
+ properties: {
+ lang: {
+ type: 'string',
+ description:
+ 'The code of the language these strings are written in.',
+ format: 'language',
+ },
+ name: {
+ type: 'string',
+ description: 'A short human-readable name for the label.',
+ maxGraphemes: 64,
+ maxLength: 640,
+ },
+ description: {
+ type: 'string',
+ description:
+ 'A longer description of what the label means and why it might be applied.',
+ maxGraphemes: 10000,
+ maxLength: 100000,
+ },
+ },
+ },
+ labelValue: {
+ type: 'string',
+ knownValues: [
+ '!hide',
+ '!no-promote',
+ '!warn',
+ '!no-unauthenticated',
+ 'dmca-violation',
+ 'doxxing',
+ 'porn',
+ 'sexual',
+ 'nudity',
+ 'nsfl',
+ 'gore',
+ ],
+ },
+ },
+ },
+ ComAtprotoRepoApplyWrites: {
+ lexicon: 1,
+ id: 'com.atproto.repo.applyWrites',
+ defs: {
+ main: {
+ type: 'procedure',
+ description:
+ 'Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.',
+ input: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['repo', 'writes'],
+ properties: {
+ repo: {
+ type: 'string',
+ format: 'at-identifier',
+ description:
+ 'The handle or DID of the repo (aka, current account).',
+ },
+ validate: {
+ type: 'boolean',
+ 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.",
+ },
+ writes: {
+ type: 'array',
+ items: {
+ type: 'union',
+ refs: [
+ 'lex:com.atproto.repo.applyWrites#create',
+ 'lex:com.atproto.repo.applyWrites#update',
+ 'lex:com.atproto.repo.applyWrites#delete',
+ ],
+ closed: true,
+ },
+ },
+ swapCommit: {
+ type: 'string',
+ 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.',
+ format: 'cid',
+ },
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: [],
+ properties: {
+ commit: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.defs#commitMeta',
+ },
+ results: {
+ type: 'array',
+ items: {
+ type: 'union',
+ refs: [
+ 'lex:com.atproto.repo.applyWrites#createResult',
+ 'lex:com.atproto.repo.applyWrites#updateResult',
+ 'lex:com.atproto.repo.applyWrites#deleteResult',
+ ],
+ closed: true,
+ },
+ },
+ },
+ },
+ },
+ errors: [
+ {
+ name: 'InvalidSwap',
+ description:
+ "Indicates that the 'swapCommit' parameter did not match current commit.",
+ },
+ ],
+ },
+ create: {
+ type: 'object',
+ description: 'Operation which creates a new record.',
+ required: ['collection', 'value'],
+ properties: {
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ },
+ rkey: {
+ type: 'string',
+ maxLength: 512,
+ format: 'record-key',
+ description:
+ 'NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility.',
+ },
+ value: {
+ type: 'unknown',
+ },
+ },
+ },
+ update: {
+ type: 'object',
+ description: 'Operation which updates an existing record.',
+ required: ['collection', 'rkey', 'value'],
+ properties: {
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ },
+ rkey: {
+ type: 'string',
+ format: 'record-key',
+ },
+ value: {
+ type: 'unknown',
+ },
+ },
+ },
+ delete: {
+ type: 'object',
+ description: 'Operation which deletes an existing record.',
+ required: ['collection', 'rkey'],
+ properties: {
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ },
+ rkey: {
+ type: 'string',
+ format: 'record-key',
+ },
+ },
+ },
+ createResult: {
+ type: 'object',
+ required: ['uri', 'cid'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ validationStatus: {
+ type: 'string',
+ knownValues: ['valid', 'unknown'],
+ },
+ },
+ },
+ updateResult: {
+ type: 'object',
+ required: ['uri', 'cid'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ validationStatus: {
+ type: 'string',
+ knownValues: ['valid', 'unknown'],
+ },
+ },
+ },
+ deleteResult: {
+ type: 'object',
+ required: [],
+ properties: {},
+ },
+ },
+ },
+ ComAtprotoRepoCreateRecord: {
+ lexicon: 1,
+ id: 'com.atproto.repo.createRecord',
+ defs: {
+ main: {
+ type: 'procedure',
+ description:
+ 'Create a single new repository record. Requires auth, implemented by PDS.',
+ input: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['repo', 'collection', 'record'],
+ properties: {
+ repo: {
+ type: 'string',
+ format: 'at-identifier',
+ description:
+ 'The handle or DID of the repo (aka, current account).',
+ },
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ description: 'The NSID of the record collection.',
+ },
+ rkey: {
+ type: 'string',
+ format: 'record-key',
+ description: 'The Record Key.',
+ maxLength: 512,
+ },
+ validate: {
+ type: 'boolean',
+ 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.",
+ },
+ record: {
+ type: 'unknown',
+ description: 'The record itself. Must contain a $type field.',
+ },
+ swapCommit: {
+ type: 'string',
+ format: 'cid',
+ description:
+ 'Compare and swap with the previous commit by CID.',
+ },
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['uri', 'cid'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ commit: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.defs#commitMeta',
+ },
+ validationStatus: {
+ type: 'string',
+ knownValues: ['valid', 'unknown'],
+ },
+ },
+ },
+ },
+ errors: [
+ {
+ name: 'InvalidSwap',
+ description:
+ "Indicates that 'swapCommit' didn't match current repo commit.",
+ },
+ ],
+ },
+ },
+ },
+ ComAtprotoRepoDefs: {
+ lexicon: 1,
+ id: 'com.atproto.repo.defs',
+ defs: {
+ commitMeta: {
+ type: 'object',
+ required: ['cid', 'rev'],
+ properties: {
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ rev: {
+ type: 'string',
+ format: 'tid',
+ },
+ },
+ },
+ },
+ },
+ ComAtprotoRepoDeleteRecord: {
+ lexicon: 1,
+ id: 'com.atproto.repo.deleteRecord',
+ defs: {
+ main: {
+ type: 'procedure',
+ description:
+ "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.",
+ input: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['repo', 'collection', 'rkey'],
+ properties: {
+ repo: {
+ type: 'string',
+ format: 'at-identifier',
+ description:
+ 'The handle or DID of the repo (aka, current account).',
+ },
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ description: 'The NSID of the record collection.',
+ },
+ rkey: {
+ type: 'string',
+ format: 'record-key',
+ description: 'The Record Key.',
+ },
+ swapRecord: {
+ type: 'string',
+ format: 'cid',
+ description:
+ 'Compare and swap with the previous record by CID.',
+ },
+ swapCommit: {
+ type: 'string',
+ format: 'cid',
+ description:
+ 'Compare and swap with the previous commit by CID.',
+ },
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ properties: {
+ commit: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.defs#commitMeta',
+ },
+ },
+ },
+ },
+ errors: [
+ {
+ name: 'InvalidSwap',
+ },
+ ],
+ },
+ },
+ },
+ ComAtprotoRepoDescribeRepo: {
+ lexicon: 1,
+ id: 'com.atproto.repo.describeRepo',
+ defs: {
+ main: {
+ type: 'query',
+ description:
+ 'Get information about an account and repository, including the list of collections. Does not require auth.',
+ parameters: {
+ type: 'params',
+ required: ['repo'],
+ properties: {
+ repo: {
+ type: 'string',
+ format: 'at-identifier',
+ description: 'The handle or DID of the repo.',
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: [
+ 'handle',
+ 'did',
+ 'didDoc',
+ 'collections',
+ 'handleIsCorrect',
+ ],
+ properties: {
+ handle: {
+ type: 'string',
+ format: 'handle',
+ },
+ did: {
+ type: 'string',
+ format: 'did',
+ },
+ didDoc: {
+ type: 'unknown',
+ description: 'The complete DID document for this account.',
+ },
+ collections: {
+ type: 'array',
+ description:
+ 'List of all the collections (NSIDs) for which this repo contains at least one record.',
+ items: {
+ type: 'string',
+ format: 'nsid',
+ },
+ },
+ handleIsCorrect: {
+ type: 'boolean',
+ description:
+ 'Indicates if handle is currently valid (resolves bi-directionally)',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ ComAtprotoRepoGetRecord: {
+ lexicon: 1,
+ id: 'com.atproto.repo.getRecord',
+ defs: {
+ main: {
+ type: 'query',
+ description:
+ 'Get a single record from a repository. Does not require auth.',
+ parameters: {
+ type: 'params',
+ required: ['repo', 'collection', 'rkey'],
+ properties: {
+ repo: {
+ type: 'string',
+ format: 'at-identifier',
+ description: 'The handle or DID of the repo.',
+ },
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ description: 'The NSID of the record collection.',
+ },
+ rkey: {
+ type: 'string',
+ description: 'The Record Key.',
+ format: 'record-key',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ description:
+ 'The CID of the version of the record. If not specified, then return the most recent version.',
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['uri', 'value'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ value: {
+ type: 'unknown',
+ },
+ },
+ },
+ },
+ errors: [
+ {
+ name: 'RecordNotFound',
+ },
+ ],
+ },
+ },
+ },
+ ComAtprotoRepoImportRepo: {
+ lexicon: 1,
+ id: 'com.atproto.repo.importRepo',
+ defs: {
+ main: {
+ type: 'procedure',
+ description:
+ 'Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.',
+ input: {
+ encoding: 'application/vnd.ipld.car',
+ },
+ },
+ },
+ },
+ ComAtprotoRepoListMissingBlobs: {
+ lexicon: 1,
+ id: 'com.atproto.repo.listMissingBlobs',
+ defs: {
+ main: {
+ type: 'query',
+ description:
+ 'Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.',
+ parameters: {
+ type: 'params',
+ properties: {
+ limit: {
+ type: 'integer',
+ minimum: 1,
+ maximum: 1000,
+ default: 500,
+ },
+ cursor: {
+ type: 'string',
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['blobs'],
+ properties: {
+ cursor: {
+ type: 'string',
+ },
+ blobs: {
+ type: 'array',
+ items: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.listMissingBlobs#recordBlob',
+ },
+ },
+ },
+ },
+ },
+ },
+ recordBlob: {
+ type: 'object',
+ required: ['cid', 'recordUri'],
+ properties: {
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ recordUri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ },
+ },
+ },
+ },
+ ComAtprotoRepoListRecords: {
+ lexicon: 1,
+ id: 'com.atproto.repo.listRecords',
+ defs: {
+ main: {
+ type: 'query',
+ description:
+ 'List a range of records in a repository, matching a specific collection. Does not require auth.',
+ parameters: {
+ type: 'params',
+ required: ['repo', 'collection'],
+ properties: {
+ repo: {
+ type: 'string',
+ format: 'at-identifier',
+ description: 'The handle or DID of the repo.',
+ },
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ description: 'The NSID of the record type.',
+ },
+ limit: {
+ type: 'integer',
+ minimum: 1,
+ maximum: 100,
+ default: 50,
+ description: 'The number of records to return.',
+ },
+ cursor: {
+ type: 'string',
+ },
+ rkeyStart: {
+ type: 'string',
+ description:
+ 'DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)',
+ },
+ rkeyEnd: {
+ type: 'string',
+ description:
+ 'DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)',
+ },
+ reverse: {
+ type: 'boolean',
+ description: 'Flag to reverse the order of the returned records.',
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['records'],
+ properties: {
+ cursor: {
+ type: 'string',
+ },
+ records: {
+ type: 'array',
+ items: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.listRecords#record',
+ },
+ },
+ },
+ },
+ },
+ },
+ record: {
+ type: 'object',
+ required: ['uri', 'cid', 'value'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ value: {
+ type: 'unknown',
+ },
+ },
+ },
+ },
+ },
+ ComAtprotoRepoPutRecord: {
+ lexicon: 1,
+ id: 'com.atproto.repo.putRecord',
+ defs: {
+ main: {
+ type: 'procedure',
+ description:
+ 'Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.',
+ input: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['repo', 'collection', 'rkey', 'record'],
+ nullable: ['swapRecord'],
+ properties: {
+ repo: {
+ type: 'string',
+ format: 'at-identifier',
+ description:
+ 'The handle or DID of the repo (aka, current account).',
+ },
+ collection: {
+ type: 'string',
+ format: 'nsid',
+ description: 'The NSID of the record collection.',
+ },
+ rkey: {
+ type: 'string',
+ format: 'record-key',
+ description: 'The Record Key.',
+ maxLength: 512,
+ },
+ validate: {
+ type: 'boolean',
+ 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.",
+ },
+ record: {
+ type: 'unknown',
+ description: 'The record to write.',
+ },
+ swapRecord: {
+ type: 'string',
+ format: 'cid',
+ description:
+ 'Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation',
+ },
+ swapCommit: {
+ type: 'string',
+ format: 'cid',
+ description:
+ 'Compare and swap with the previous commit by CID.',
+ },
+ },
+ },
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['uri', 'cid'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ commit: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.defs#commitMeta',
+ },
+ validationStatus: {
+ type: 'string',
+ knownValues: ['valid', 'unknown'],
+ },
+ },
+ },
+ },
+ errors: [
+ {
+ name: 'InvalidSwap',
+ },
+ ],
+ },
+ },
+ },
+ ComAtprotoRepoStrongRef: {
+ lexicon: 1,
+ id: 'com.atproto.repo.strongRef',
+ description: 'A URI with a content-hash fingerprint.',
+ defs: {
+ main: {
+ type: 'object',
+ required: ['uri', 'cid'],
+ properties: {
+ uri: {
+ type: 'string',
+ format: 'at-uri',
+ },
+ cid: {
+ type: 'string',
+ format: 'cid',
+ },
+ },
+ },
+ },
+ },
+ ComAtprotoRepoUploadBlob: {
+ lexicon: 1,
+ id: 'com.atproto.repo.uploadBlob',
+ defs: {
+ main: {
+ type: 'procedure',
+ 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.',
+ input: {
+ encoding: '*/*',
+ },
+ output: {
+ encoding: 'application/json',
+ schema: {
+ type: 'object',
+ required: ['blob'],
+ properties: {
+ blob: {
+ type: 'blob',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ AppBskyActorDefs: {
+ lexicon: 1,
+ id: 'app.bsky.actor.defs',
+ defs: {
+ profileView: {
+ type: 'object',
+ required: ['did', 'handle'],
+ properties: {
+ did: {
+ type: 'string',
+ format: 'did',
+ },
+ handle: {
+ type: 'string',
+ format: 'handle',
+ },
+ displayName: {
+ type: 'string',
+ maxGraphemes: 64,
+ maxLength: 640,
+ },
+ description: {
+ type: 'string',
+ maxGraphemes: 256,
+ maxLength: 2560,
+ },
+ avatar: {
+ type: 'string',
+ format: 'uri',
+ },
+ indexedAt: {
+ type: 'string',
+ format: 'datetime',
+ },
+ createdAt: {
+ type: 'string',
+ format: 'datetime',
+ },
+ labels: {
+ type: 'array',
+ items: {
+ type: 'ref',
+ ref: 'lex:com.atproto.label.defs#label',
+ },
+ },
+ },
+ },
+ },
+ },
+ AppBskyActorProfile: {
+ lexicon: 1,
+ id: 'app.bsky.actor.profile',
+ defs: {
+ main: {
+ type: 'record',
+ description: 'A declaration of a Bluesky account profile.',
+ key: 'literal:self',
+ record: {
+ type: 'object',
+ properties: {
+ displayName: {
+ type: 'string',
+ maxGraphemes: 64,
+ maxLength: 640,
+ },
+ description: {
+ type: 'string',
+ description: 'Free-form profile description text.',
+ maxGraphemes: 256,
+ maxLength: 2560,
+ },
+ avatar: {
+ type: 'blob',
+ description:
+ "Small image to be displayed next to posts from account. AKA, 'profile picture'",
+ accept: ['image/png', 'image/jpeg'],
+ maxSize: 1000000,
+ },
+ banner: {
+ type: 'blob',
+ description:
+ 'Larger horizontal image to display behind profile view.',
+ accept: ['image/png', 'image/jpeg'],
+ maxSize: 1000000,
+ },
+ labels: {
+ type: 'union',
+ description:
+ 'Self-label values, specific to the Bluesky application, on the overall account.',
+ refs: ['lex:com.atproto.label.defs#selfLabels'],
+ },
+ joinedViaStarterPack: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.strongRef',
+ },
+ pinnedPost: {
+ type: 'ref',
+ ref: 'lex:com.atproto.repo.strongRef',
+ },
+ createdAt: {
+ type: 'string',
+ format: 'datetime',
+ },
+ },
+ },
+ },
+ },
+ },
} as const satisfies Record
export const schemas = Object.values(schemaDict) satisfies LexiconDoc[]
@@ -59,5 +1288,25 @@ export function validate(
}
export const ids = {
+ XyzStatusphereDefs: 'xyz.statusphere.defs',
+ XyzStatusphereGetStatuses: 'xyz.statusphere.getStatuses',
+ XyzStatusphereGetUser: 'xyz.statusphere.getUser',
+ XyzStatusphereSendStatus: 'xyz.statusphere.sendStatus',
+ XyzStatusphereStatus: 'xyz.statusphere.status',
AppAndrefAtmiiMii: 'app.andref.atmii.mii',
+ ComAtprotoLabelDefs: 'com.atproto.label.defs',
+ ComAtprotoRepoApplyWrites: 'com.atproto.repo.applyWrites',
+ ComAtprotoRepoCreateRecord: 'com.atproto.repo.createRecord',
+ ComAtprotoRepoDefs: 'com.atproto.repo.defs',
+ ComAtprotoRepoDeleteRecord: 'com.atproto.repo.deleteRecord',
+ ComAtprotoRepoDescribeRepo: 'com.atproto.repo.describeRepo',
+ ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord',
+ ComAtprotoRepoImportRepo: 'com.atproto.repo.importRepo',
+ ComAtprotoRepoListMissingBlobs: 'com.atproto.repo.listMissingBlobs',
+ ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords',
+ ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord',
+ ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef',
+ ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob',
+ AppBskyActorDefs: 'app.bsky.actor.defs',
+ AppBskyActorProfile: 'app.bsky.actor.profile',
} as const
diff --git a/experimental/atmii/packages/lexicon/src/types/app/bsky/actor/defs.ts b/experimental/atmii/packages/lexicon/src/types/app/bsky/actor/defs.ts
new file mode 100644
index 0000000..5f65150
--- /dev/null
+++ b/experimental/atmii/packages/lexicon/src/types/app/bsky/actor/defs.ts
@@ -0,0 +1,35 @@
+/**
+ * GENERATED CODE - DO NOT MODIFY
+ */
+import { BlobRef, ValidationResult } from '@atproto/lexicon'
+import { CID } from 'multiformats/cid'
+
+import { validate as _validate } from '../../../../lexicons'
+import { is$typed as _is$typed, $Typed, OmitKey } from '../../../../util'
+import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js'
+
+const is$typed = _is$typed,
+ validate = _validate
+const id = 'app.bsky.actor.defs'
+
+export interface ProfileView {
+ $type?: 'app.bsky.actor.defs#profileView'
+ did: string
+ handle: string
+ displayName?: string
+ description?: string
+ avatar?: string
+ indexedAt?: string
+ createdAt?: string
+ labels?: ComAtprotoLabelDefs.Label[]
+}
+
+const hashProfileView = 'profileView'
+
+export function isProfileView(v: V) {
+ return is$typed(v, id, hashProfileView)
+}
+
+export function validateProfileView(v: V) {
+ return validate(v, id, hashProfileView)
+}
diff --git a/experimental/atmii/packages/lexicon/src/types/app/bsky/actor/profile.ts b/experimental/atmii/packages/lexicon/src/types/app/bsky/actor/profile.ts
new file mode 100644
index 0000000..579bcae
--- /dev/null
+++ b/experimental/atmii/packages/lexicon/src/types/app/bsky/actor/profile.ts
@@ -0,0 +1,40 @@
+/**
+ * GENERATED CODE - DO NOT MODIFY
+ */
+import { BlobRef, ValidationResult } from '@atproto/lexicon'
+import { CID } from 'multiformats/cid'
+
+import { validate as _validate } from '../../../../lexicons'
+import { is$typed as _is$typed, $Typed, OmitKey } from '../../../../util'
+import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js'
+import type * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef.js'
+
+const is$typed = _is$typed,
+ validate = _validate
+const id = 'app.bsky.actor.profile'
+
+export interface Record {
+ $type: 'app.bsky.actor.profile'
+ displayName?: string
+ /** Free-form profile description text. */
+ description?: string
+ /** Small image to be displayed next to posts from account. AKA, 'profile picture' */
+ avatar?: BlobRef
+ /** Larger horizontal image to display behind profile view. */
+ banner?: BlobRef
+ labels?: $Typed | { $type: string }
+ joinedViaStarterPack?: ComAtprotoRepoStrongRef.Main
+ pinnedPost?: ComAtprotoRepoStrongRef.Main
+ createdAt?: string
+ [k: string]: unknown
+}
+
+const hashRecord = 'main'
+
+export function isRecord(v: V) {
+ return is$typed(v, id, hashRecord)
+}
+
+export function validateRecord(v: V) {
+ return validate(v, id, hashRecord, true)
+}
diff --git a/experimental/atmii/packages/lexicon/src/types/com/atproto/label/defs.ts b/experimental/atmii/packages/lexicon/src/types/com/atproto/label/defs.ts
new file mode 100644
index 0000000..af45f4a
--- /dev/null
+++ b/experimental/atmii/packages/lexicon/src/types/com/atproto/label/defs.ts
@@ -0,0 +1,143 @@
+/**
+ * GENERATED CODE - DO NOT MODIFY
+ */
+import { BlobRef, ValidationResult } from '@atproto/lexicon'
+import { CID } from 'multiformats/cid'
+
+import { validate as _validate } from '../../../../lexicons'
+import { is$typed as _is$typed, $Typed, OmitKey } from '../../../../util'
+
+const is$typed = _is$typed,
+ validate = _validate
+const id = 'com.atproto.label.defs'
+
+/** Metadata tag on an atproto resource (eg, repo or record). */
+export interface Label {
+ $type?: 'com.atproto.label.defs#label'
+ /** The AT Protocol version of the label object. */
+ ver?: number
+ /** DID of the actor who created this label. */
+ src: string
+ /** AT URI of the record, repository (account), or other resource that this label applies to. */
+ uri: string
+ /** Optionally, CID specifying the specific version of 'uri' resource this label applies to. */
+ cid?: string
+ /** The short string name of the value or type of this label. */
+ val: string
+ /** If true, this is a negation label, overwriting a previous label. */
+ neg?: boolean
+ /** Timestamp when this label was created. */
+ cts: string
+ /** Timestamp at which this label expires (no longer applies). */
+ exp?: string
+ /** Signature of dag-cbor encoded label. */
+ sig?: Uint8Array
+}
+
+const hashLabel = 'label'
+
+export function isLabel(v: V) {
+ return is$typed(v, id, hashLabel)
+}
+
+export function validateLabel(v: V) {
+ return validate