Reference
Evaluation harness
This document covers the browser harness, sample store, local provider, and storage-layout benchmark.
Run the browser harness
npm install
npm run dev
Open http://127.0.0.1:5173.
Configure Entra or a generic OIDC provider, obtain an API access token through the provider’s application flow, select the provider in the harness, and exchange the token for a ThimbleDB session.
The Playwright suite includes a self-contained signed test provider:
npm run test:e2e
The UI can:
- seed a deterministic online-store dataset
- read one product through memory, IndexedDB, and object storage
- switch between no cache, location-only cache, and full-content cache
- run 100 hot reads or a collection scan
- clear memory separately from persistent cache
- mutate product stock through the authority
- delete and restore retained documents
- link external identities and use administrator controls
- compare trie and snapshot collection behaviour
- display remote reads, transferred bytes, cache hits, ETag 304 responses, offline fallbacks, and retained memory
For a compiled local run:
npm run build
$env:THIMBLE_ALLOWED_ORIGIN = "http://127.0.0.1:8787"
npm run start:prod
Open http://127.0.0.1:8787.
Local durable objects are stored below .thimble-data. The adapter serialises
access only inside one Node process.
Local encryption behaviour
Encrypted scope mode is the default.
On first local startup:
- The authority creates a local deployment master key under
.thimble-data. - It derives one scope encryption key and one node-address HMAC key.
- A validated external identity is mapped to a stable internal user UUID.
- The browser receives an HttpOnly opaque session cookie.
- The authorised key endpoint returns the scope key once.
- The browser imports it as a non-extractable memory-only CryptoKey.
- Persistent cache values are encrypted with a separate non-extractable browser device key.
Raw stored objects begin with the TDB1 envelope magic and do not contain
plaintext JSON.
Browser cache policies
| Policy | Cached objects | Purpose |
|---|---|---|
none | Nothing | Cold process or cache-miss measurement |
locations | HEAD plus root and branch routing nodes | Avoid path discovery while loading current leaf content |
content | All fetched objects | Warm read-mostly application |
Mutable HEAD uses a configurable TTL:
$env:THIMBLE_HEAD_TTL_MS = "1000"
Per-collection and per-object TTL policy is a future extension.
Sample application
The deterministic store contains:
- products with categories, stock, descriptions, and prices
- customers with addresses
- orders with line items
The browser harness uses the same data generator as the storage-layout benchmark.
Use Azure in the harness
For a browser test against Azure:
$env:THIMBLE_PROVIDER = "azure"
$env:AZURE_STORAGE_CONNECTION_STRING = "<server-only connection string>"
$env:AZURE_STORAGE_CONTAINER = "thimbledb"
$env:AZURE_AUTH_STORAGE_CONTAINER = "thimbledb-auth"
$env:THIMBLE_PREFIX = "demo"
$env:THIMBLE_MASTER_KEY = "<base64-encoded 32-byte key>"
$env:THIMBLE_ALLOWED_ORIGIN = "http://127.0.0.1:5173"
$env:ENTRA_TENANT_ID = "<tenant-id>"
$env:ENTRA_AUDIENCE = "<api-audience>"
$env:ENTRA_REQUIRED_SCOPE = "thimble.access"
npm run dev
Private objects are read through the authenticated authority. The auth container is never exposed to the browser.
See Deploy to Azure for the complete path.
Storage-layout benchmark
The storage benchmark compares:
| Engine | Storage model | Expected strength | Expected weakness |
|---|---|---|---|
| Monolithic JSON | One mutable object per collection | Minimal requests and excellent scans | Rewrites the collection and has severe write contention |
| Append log + snapshot | Immutable numbered log entries and periodic snapshots | Efficient append behaviour | Reads replay the uncompacted tail |
| Content-addressed trie | Immutable two-level trie and CAS-updated root | Small point-read payloads and structural sharing | More requests, root contention, and garbage collection |
The log model is inspired by Baerly’s documented protocol but is not a compatibility implementation.
Workload
Each engine:
- seeds products, customers, and orders
- runs cold, location-cached, and content-cached point reads
- runs catalogue scans under each cache policy
- applies sequential updates
- races concurrent writes
- runs checkout-shaped reads and writes
- runs maintenance and verifies data afterwards
The harness records:
- elapsed time and p50/p95 latency
- GET, PUT, DELETE, and LIST operations
- bytes read and written
- cache hits and retained bytes
- failed conditional writes and retries
- final object count and stored bytes
Run locally
npm run benchmark:local
npm run benchmark -- --provider local --profile small --latency-ms 8
Run against S3 or R2 through the S3 API
$env:S3_BUCKET = "<bucket>"
$env:AWS_REGION = "us-east-1"
npm run benchmark -- --provider s3 --profile small
R2:
$env:S3_BUCKET = "<r2-bucket>"
$env:AWS_REGION = "auto"
$env:S3_ENDPOINT = "https://<account-id>.r2.cloudflarestorage.com"
npm run benchmark -- --provider s3 --profile small
The benchmark uses the normal AWS credential chain. Do not put credentials in command arguments or source files.
Published evidence
Published benchmark artifacts cover live multi-region browser runs against the Cloudflare/R2 reference deployment.
See Benchmarks for the measured table, interpretation, limitations, and layout decision thresholds.
Comparative application harness
The repository also contains one deterministic bounded-notes scenario:
npm run benchmark:compare:local
The checked-in smoke adapters use:
- the local immutable snapshot engine
- Node’s in-memory SQLite implementation
Raw JSON is written below the ignored benchmark-results directory. These
local timings exercise different architectures and do not establish product
performance or cost superiority.
Cloudflare D1 and Firestore comparisons require matched deployed resources, regions, datasets, warm-up policy, and evidence capture before their results can support a public claim.
What the harness does not model
The harness does not model:
- production-scale authentication traffic
- sustained multi-region write contention
- cross-collection transactions
- search or analytics
- residential last-mile latency
- cost or latency superiority over managed databases