1{2 "$schema": "http://json-schema.org/draft-07/schema#",3 "$id": "https://bind.ws/relay-config.schema.json",4 "title": "bind.ws relay configuration",5 "description": "A relay's rules, identity, people, lists and app shortcuts as one document: what exportconfig writes and importconfig reads. A section left out is left alone. The relay's parser (src/config.ts) is the last word; this schema is for the editor.",6 "type": "object",7 "required": ["format"],8 "additionalProperties": false,9 "properties": {10 "$schema": { "type": "string" },11 "format": { "enum": ["bind.ws/relay-config/1", "bind.ws/relay-config/2"] },12 "exported_at": { "type": "integer", "description": "when the relay wrote it; ignored on import" },13 "name": { "type": "string", "maxLength": 64, "description": "the relay's name at export; ignored on import" },14 "template": {15 "type": "object",16 "description": "present on a template in relay-templates/: how the console presents it",17 "required": ["title", "about"],18 "additionalProperties": false,19 "properties": {20 "title": { "type": "string", "maxLength": 80 },21 "about": { "type": "string", "maxLength": 400 },22 "source": { "enum": ["required", "optional"], "description": "a replica pulls from a source relay: required, or optional" },23 "every": { "type": "integer", "minimum": 1, "description": "hours between pulls" }24 }25 },26 "policy": {27 "type": "object",28 "additionalProperties": false,29 "properties": {30 "name": { "type": "string", "maxLength": 2000 },31 "description": { "type": "string", "maxLength": 2000 },32 "icon": { "type": "string", "maxLength": 2000 },33 "banner": { "type": "string" },34 "contact": { "type": "string", "maxLength": 2000 },35 "postingPolicy": { "type": "string" },36 "privacyPolicy": { "type": "string" },37 "tags": { "type": "array", "items": { "type": "string" } },38 "languageTags": { "type": "array", "items": { "type": "string" } },39 "relayCountries": { "type": "array", "items": { "type": "string" } },40 "notify": { "type": "object", "additionalProperties": { "type": "boolean" } },41 "writes": { "enum": ["open", "allowlist", "wot", "owner"] },42 "openKinds": { "type": "array", "items": { "$ref": "#/definitions/kind" } },43 "guestReplies": { "type": "boolean" },44 "blockedWords": { "type": "array", "items": { "type": "string", "maxLength": 200 } },45 "blockedWordsInTags": { "type": "boolean" },46 "reportThreshold": { "type": "integer", "minimum": 0 },47 "reads": { "enum": ["open", "auth", "members"] },48 "joinTerms": { "type": "string", "maxLength": 20000 },49 "directoryPublic": { "type": "boolean" },50 "maxBlobMB": { "type": "integer", "minimum": 1, "maximum": 95 },51 "git": {52 "type": "object",53 "description": "GRASP Git retained-storage and request limits. Byte fields are bytes; these maxima mirror src/git-limits.ts.",54 "additionalProperties": false,55 "properties": {56 "maxRepositories": { "type": "integer", "minimum": 1, "maximum": 4096, "description": "Maximum accepted repositories on this relay." },57 "maxRelayBytes": { "type": "integer", "minimum": 1, "maximum": 6442450944, "description": "Total retained Git bytes, including compressed objects and metadata." },58 "maxPackBytes": { "type": "integer", "minimum": 1, "maximum": 99614720, "description": "Maximum pack upload or response size." },59 "maxObjectBytes": { "type": "integer", "minimum": 1, "maximum": 67108864, "description": "Maximum one Git object body." },60 "maxObjects": { "type": "integer", "minimum": 1, "maximum": 500000 },61 "maxRawBytes": { "type": "integer", "minimum": 1, "maximum": 68719476736 },62 "maxTransactionRawBytes": { "type": "integer", "minimum": 1, "maximum": 67108864 },63 "maxTransactionObjects": { "type": "integer", "minimum": 1, "maximum": 100000 },64 "maxCompressedBytes": { "type": "integer", "minimum": 1, "maximum": 6442450944, "description": "Retained compressed Git object payload per repository." },65 "maxMetadataBytes": { "type": "integer", "minimum": 1, "maximum": 1073741824 },66 "maxRefs": { "type": "integer", "minimum": 1, "maximum": 16384 },67 "maxGraphEdges": { "type": "integer", "minimum": 1, "maximum": 4000000 },68 "maxFetchBytes": { "type": "integer", "minimum": 1, "maximum": 6442450944 }69 }70 },71 "eventsPerMinute": { "type": "integer", "minimum": 1 },72 "reqsPerMinute": { "type": "integer", "minimum": 1 },73 "minPow": { "type": "integer", "minimum": 0, "maximum": 64 },74 "maxFuture": { "type": "integer", "minimum": 0 },75 "maxLimit": { "type": "integer", "minimum": 1, "maximum": 5000 },76 "maxSubs": { "type": "integer", "minimum": 1, "maximum": 200 },77 "maxMessageKB": { "type": "integer", "minimum": 16, "maximum": 1024 },78 "dumps": { "enum": ["off", "daily", "weekly"] },79 "dumpsKeep": { "type": "integer", "minimum": 1, "maximum": 60 },80 "memberInvites": {81 "type": "object",82 "additionalProperties": false,83 "properties": { "depth": { "type": "integer", "minimum": 0 }, "quota": { "type": "integer", "minimum": 0 } }84 },85 "views": { "type": "object", "additionalProperties": { "anyOf": [{ "type": "boolean" }, { "enum": ["off", "write", "hourly", "daily"] }] }, "description": "a view named here runs on that trigger, or is off; the rest run on their own trigger. true and false still mean the default and off" },86 "pushCallbacks": { "type": "array", "maxItems": 16, "items": { "type": "string", "maxLength": 2048 }, "description": "Exact HTTPS callback origins, also approved by the host operator" },87 "letteredNips": { "type": "boolean", "description": "Mixed numeric and lettered NIP-11 identifiers. Push also activates this representation." },88 "features": {89 "type": "object",90 "additionalProperties": false,91 "properties": {92 "search": { "enum": ["full", "prose", "off"] },93 "sync": { "type": "boolean" },94 "count": { "type": "boolean" },95 "discovery": { "type": "boolean" },96 "names": { "type": "boolean" },97 "files": { "type": "boolean" },98 "pages": { "type": "boolean" },99 "signer": { "type": "boolean" },100 "marmot": { "type": "boolean" },101 "sites": {102 "oneOf": [103 { "type": "boolean" },104 { "type": "object", "additionalProperties": false, "properties": {105 "enabled": { "type": "boolean" }, "mirror": { "type": "boolean" }106 } }107 ]108 },109 "grasp": { "type": "boolean" },110 "grasp02": { "type": "boolean" },111 "grasp03": { "type": "boolean" },112 "grasp05": { "type": "boolean" },113 "grasp06": { "type": "boolean" },114 "push": { "type": "boolean" }115 }116 }117 }118 },119 "members": {120 "type": "array",121 "items": {122 "type": "object",123 "required": ["pubkey"],124 "additionalProperties": false,125 "properties": {126 "pubkey": { "$ref": "#/definitions/hex64" },127 "name": { "type": ["string", "null"] },128 "note": { "type": "string", "maxLength": 2000 },129 "role": { "enum": ["member", "moderator"] },130 "keepDays": { "type": "integer", "minimum": 1 },131 "maxBytes": { "type": "integer", "minimum": 1 }132 }133 }134 },135 "bans": { "type": "array", "items": { "$ref": "#/definitions/pubkeyEntry" } },136 "banned_events": {137 "type": "array",138 "items": { "type": "object", "required": ["id"], "additionalProperties": false, "properties": { "id": { "$ref": "#/definitions/hex64" }, "reason": { "type": "string", "maxLength": 200 } } }139 },140 "addresses": {141 "type": "array",142 "items": { "type": "object", "required": ["ip"], "additionalProperties": false, "properties": { "ip": { "type": "string" }, "reason": { "type": "string", "maxLength": 200 } } }143 },144 "kinds": {145 "type": "object",146 "additionalProperties": false,147 "properties": { "allow": { "type": "array", "items": { "$ref": "#/definitions/kind" } }, "block": { "type": "array", "items": { "$ref": "#/definitions/kind" } } }148 },149 "retention": {150 "type": "array",151 "items": { "type": "object", "required": ["kind", "days"], "additionalProperties": false, "properties": { "kind": { "oneOf": [{ "$ref": "#/definitions/kind" }, { "type": "null" }] }, "days": { "type": "integer", "minimum": 1, "maximum": 36500 } } }152 },153 "connections": {154 "type": "array",155 "maxItems": 24,156 "description": "the Connect fold's app shortcuts, in order: each names a connection template from connection-templates/",157 "items": {158 "type": "object",159 "required": ["template"],160 "additionalProperties": false,161 "properties": {162 "template": { "type": "string", "pattern": "^[a-z0-9-]{1,40}$", "description": "a file in connection-templates/, by name" },163 "visibility": { "enum": ["public", "auth", "members", "owner"], "description": "who sees it: anyone, anyone signed in, members, the owner; the template's own when left out" },164 "title": { "type": "string", "maxLength": 40, "description": "the owner's title instead of the template's" },165 "about": { "type": "string", "maxLength": 200, "description": "the owner's sentence instead of the template's" },166 "inputs": { "type": "object", "additionalProperties": { "type": "string", "maxLength": 500 }, "description": "the template's inputs, by name" }167 }168 }169 }170 },171 "definitions": {172 "hex64": { "type": "string", "pattern": "^[0-9a-f]{64}$" },173 "kind": { "type": "integer", "minimum": 0, "maximum": 65535 },174 "pubkeyEntry": { "type": "object", "required": ["pubkey"], "additionalProperties": false, "properties": { "pubkey": { "$ref": "#/definitions/hex64" }, "reason": { "type": "string", "maxLength": 200 } } }175 }176}