Data.ridaField values, and nothing else.
Upload this one to the publisher's server or CDN.
The shared RIDA file format stores field values as independent blocks. The data file begins with the first value byte; every boundary comes from the index held by the reader.
Data.ridaUpload this one to the publisher's server or CDN.
Index.ridaStays with the reader: record count, codec, lengths, flags and digest.
Map.jsonOptional plain JSON for folder names and field names.
Key.ridaOnly for encrypted builds. Keep it private.
Each value is compact JSON, then a raw deflate stream, then optionally sealed with AES-256-GCM. Compression must happen first because ciphertext does not compress.
JSON bytes → deflate → [ AES-256-GCM ] → stored bytesThe gzip wrapper adds 18 bytes per value: magic, time, OS metadata and a CRC that RIDA does not need. The codec already lives in the index.
| Bytes | Field | Meaning |
|---|---|---|
| 0–7 | magic | RIDAIDX1 |
| 8–11 | index_version | 1 |
| 20–23 | record_count | Records in the file |
| 24–31 | data_length | Exact data file size |
| 32–35 | codec_code | 1 deflate, 2 plain |
| 36–39 | flags | Bit 0 means encrypted |
| 40–71 | data_digest | SHA-256 or zeros |
Read the row offset for the requested record.
Walk the row to the wanted field and accumulate its position.
Add that position to the record's data start and read its length.
Ask the server for exactly that byte range; decode locally.
Opening the dataset costs zero requests. A single field costs one range request.
Failed decryption or decompression is caught before JSON is parsed.
Changing the field set is a rebuild; that is what keeps lookup at one request.
The index holds byte addresses. The map holds the names behind numbered folder prefixes and field IDs. These are separate jobs. A folder build can produce a map like this:
{
"version": 1,
"records": 600,
"paths": { "1": "catalog", "1/1": "products", "1/1/1": "items" },
"fields": { "1": "title", "2": "price", "3": "description" }
}The reader can resolve a name such as catalog/products/5 to the numbered record. A map is optional: datasets whose IDs already are their record names need none. When a folder map is unavailable, use the numbered IDs.
data.get("1/1/1/5", "title")
data.get("catalog/products/5", "title")
data.resolve("catalog", "products")
data.records_under("1/1")
data.folders()For the conventional record subfolder, the name lookup can omit that level. Naming a folder without a record number returns its first record. Keep the map beside the reader’s dataset files when using name lookups.