appName: strfry quadrable: true onAppStartup: true flatBuffers: | include "../fbs/nostr-index.fbs"; includes: | inline std::string_view sv(const NostrIndex::Fixed32Bytes *f) { return std::string_view((const char *)f->val()->data(), 32); } tables: ## DB meta-data. Single entry, with id = 1 Meta: fields: - name: dbVersion - name: endianness ## Meta-info of nostr events, suitable for indexing ## Primary key is auto-incremented, called "levId" for Local EVent ID Event: fields: - name: receivedAt # microseconds - name: flat type: ubytes nestedFlat: NostrIndex.Event indices: created_at: integer: true id: comparator: StringUint64 pubkey: comparator: StringUint64 kind: comparator: Uint64Uint64 pubkeyKind: comparator: StringUint64Uint64 tag: comparator: StringUint64 multi: true deletion: # eventId, pubkey multi: true indexPrelude: | auto *flat = v.flat_nested(); created_at = flat->created_at(); uint64_t indexTime = *created_at; id = makeKey_StringUint64(sv(flat->id()), indexTime); pubkey = makeKey_StringUint64(sv(flat->pubkey()), indexTime); kind = makeKey_Uint64Uint64(flat->kind(), indexTime); pubkeyKind = makeKey_StringUint64Uint64(sv(flat->pubkey()), flat->kind(), indexTime); for (const auto &tagPair : *(flat->tagsGeneral())) { auto tagName = (char)tagPair->key(); auto tagVal = sv(tagPair->val()); tag.push_back(makeKey_StringUint64(std::string(1, tagName) + std::string(tagVal), indexTime)); } for (const auto &tagPair : *(flat->tagsFixed32())) { auto tagName = (char)tagPair->key(); auto tagVal = sv(tagPair->val()); tag.push_back(makeKey_StringUint64(std::string(1, tagName) + std::string(tagVal), indexTime)); if (flat->kind() == 5 && tagName == 'e') deletion.push_back(std::string(tagVal) + std::string(sv(flat->pubkey()))); } CompressionDictionary: fields: - name: dict type: ubytes tablesRaw: ## Raw nostr event JSON, possibly compressed ## keys are levIds ## vals are prefixed with a type byte: ## 0: no compression, payload follows ## 1: zstd compression. Followed by Dictionary ID (native endian uint32) then compressed payload EventPayload: flags: 'MDB_INTEGERKEY' config: - name: db desc: "Directory that contains strfry database" default: "./strfry-db/" noReload: true - name: relay__bind desc: "Interface to listen on. Use 0.0.0.0 to listen on all interfaces" default: "127.0.0.1" noReload: true - name: relay__port desc: "Port to open for the nostr websocket protocol" default: 7777 noReload: true - name: relay__info__name desc: "NIP-11: Name of this server. Short/descriptive (< 30 characters)" default: "strfry default" - name: relay__info__description desc: "NIP-11: Detailed information about relay, free-form" default: "This is a strfry instance." - name: relay__info__pubkey desc: "NIP-11: Administrative nostr pubkey, for contact purposes" default: "unset" - name: relay__info__contact desc: "NIP-11: Alternative administrative contact (email, website, etc)" default: "unset" - name: relay__maxWebsocketPayloadSize desc: "Maximum accepted incoming websocket frame size (should be larger than max event and yesstr msg)" default: 131072 noReload: true - name: relay__autoPingSeconds desc: "Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts)" default: 55 noReload: true - name: relay__enableTcpKeepalive desc: "If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy)" default: false - name: relay__queryTimesliceBudgetMicroseconds desc: "How much uninterrupted CPU time a REQ query should get during its DB scan" default: 10000 - name: relay__maxFilterLimit desc: "Maximum records that can be returned per filter" default: 500 - name: relay__logging__dumpInAll desc: "Dump all incoming messages" default: false - name: relay__logging__dumpInEvents desc: "Dump all incoming EVENT messages" default: false - name: relay__logging__dumpInReqs desc: "Dump all incoming REQ/CLOSE messages" default: false - name: relay__logging__dbScanPerf desc: "Log performance metrics for initial REQ database scans" default: false - name: relay__numThreads__ingester desc: Ingester threads: route incoming requests, validate events/sigs default: 3 noReload: true - name: relay__numThreads__reqWorker desc: reqWorker threads: Handle initial DB scan for events default: 3 noReload: true - name: relay__numThreads__reqMonitor desc: reqMonitor threads: Handle filtering of new events default: 3 noReload: true - name: relay__numThreads__yesstr desc: yesstr threads: Experimental yesstr protocol default: 1 noReload: true - name: events__maxEventSize desc: "Maximum size of normalised JSON, in bytes" default: 65536 - name: events__rejectEventsNewerThanSeconds desc: "Events newer than this will be rejected" default: 900 # 15 mins - name: events__rejectEventsOlderThanSeconds desc: "Events older than this will be rejected" default: 94608000 # 3 years - name: events__rejectEphemeralEventsOlderThanSeconds desc: "Ephemeral events older than this will be rejected" default: 60 - name: events__ephemeralEventsLifetimeSeconds desc: "Ephemeral events will be deleted from the DB when older than this" default: 300 - name: events__maxNumTags desc: "Maximum number of tags allowed" default: 250 - name: events__maxTagValSize desc: "Maximum size for tag values, in bytes" default: 255