{
"id": "dev.atfs.server",
"defs": {
"main": {
"key": "any",
"type": "record",
"record": {
"type": "object",
"properties": {
"ipfs": {
"type": "object",
"properties": {
"port": {
"type": "integer",
"description": "The libp2p listen port (tcp+quic). Zero, or an absent ipfs object, means the default (4001)."
}
},
"description": "This instance's boxo/libp2p participation config."
},
"follows": {
"type": "array",
"items": {
"type": "string",
"format": "at-uri"
},
"description": "Other atfs instances this one mirrors, each named by the at-uri of that instance's own dev.atfs.server record (at://{their-owner}/dev.atfs.server/{their-peer-id}). Identity rather than a URL, so a followed instance can move endpoints without breaking the follow: the follower resolves this record to learn where to poll (its endpoints) and whose name to hold the mirrored claims under (its serviceDid, or an identity derived from its peer ID when it declares none). The follower periodically walks the followed instance's dev.atfs.repo.listFiles, pins whatever is new, and releases whatever has been absent from two consecutive listings. Following is unilateral and needs no consent: listFiles is public and every pinned cid is already a DHT provider record, so an opt-in would be unenforceable. Only directly-claimed content is exported by listFiles, so following an instance never transitively mirrors what *it* follows — follow each origin you want. Removing an entry releases every claim that instance's mirror held here, and the content is deleted once nothing else claims it."
},
"accounts": {
"type": "array",
"items": {
"type": "string",
"format": "at-identifier"
},
"description": "atproto accounts (DIDs or handles), beyond the owner, allowed to upload. The owner can always upload regardless of whether it's listed here."
},
"endpoints": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"description": "Advisory HTTPS base URLs (not full URLs — each is expected to answer both /ipfs/<cid> and a dev.atfs.repo.getFile-style XRPC) this instance is reachable at, ordered by operator preference with the primary public base URL first. Lets an app discovering this record know where to POST without resolving the instance's DID first — the same purpose dev.atfs.file's providers field serves for individual files. The first entry also feeds the instance's did:web self-serve document's serviceEndpoint, when serviceDid is a did:web (served at /.well-known/did.json). Never required for correctness: it's a hint, not a substitute for DID-based discovery."
},
"serviceDid": {
"type": "string",
"format": "did",
"description": "This instance's own DID: the `aud` uploaders must address in their inter-service auth JWTs. Uploads are disabled entirely until this is set."
}
}
}
}
},
"$type": "com.atproto.lexicon.schema",
"lexicon": 1,
"description": "An atfs instance's own configuration, read at boot — and re-read whenever it changes, the instance having subscribed to the owner's repo — by the instance whose libp2p peer ID is the record key (rkey) — at://{owner-did}/dev.atfs.server/{peer-id}. One owner repo can configure many instances this way. Changes to accounts, serviceDid and follows apply without a restart; ipfs.port is bound at startup and needs one. Unknown fields are tolerated and ignored, so a running instance is never broken by a schema field it predates. All fields are optional; an absent record is not an error — the instance runs with defaults, and uploads stay disabled until serviceDid is set."
}