| Where | URL |
|---|---|
| On a running node | http://<admin-addr>/docs (default http://127.0.0.1:8080/docs) |
| GitHub Pages | https://code0987.github.io/supercache/ |
| OpenAPI YAML (admin) | /openapi.yaml or /docs/admin.openapi.yaml |
| OpenAPI YAML (cache ref) | /docs/cache.openapi.yaml |
go run ./cmd/supercache-node \
-cache 127.0.0.1:9000 -peer 127.0.0.1:9001 -admin 127.0.0.1:8080
# open http://127.0.0.1:8080/docs| Spec | Source | Try it out? |
|---|---|---|
| Admin HTTP | api/openapi/admin.openapi.yaml |
Yes (against the node) |
| Cache gRPC | api/openapi/cache.openapi.yaml |
No — reference only |
- Go:
pkg/client - Python:
clients/python(import supercache, sync). Install from source; not published. - Node.js:
clients/node(@code0987/supercache, Promises, Node 22+). Install from source; the package isprivate. - CLI:
cmd/sc(sc get/put/del,bloom,sadd…,zadd…,geoadd…,lpush…,hset…,incr/cget,jsonset…,bitset…,vadd…,xadd…, or REPL) - Protos:
api/proto/cache.proto,api/proto/peer.proto(peer is mesh-internal)
Python and Node speak the Cache port only. They follow pkg/client: a Get with found=false raises NotFound. A gRPC status is a different error, including NOT_FOUND when the keyspace is missing (supercache: keyspace not found). PutMany / DeleteMany per-key failures and Delete peer failures are raised from the response body, not from the status. Omitted TTL leaves ttl_set false. An explicit zero TTL sets ttl_set and stores no expiry.
scripts/check-client-surface.py fails CI unless every Cache RPC below is wrapped by both clients and named in this file: Get, Put, PutMany, Delete, DeleteMany, BloomAdd, BloomTest, SetAdd, SetRemove, SetContains, SetCard, SetMembers, ZAdd, ZRem, ZScore, ZCard, ZRange, ZRangeByScore, GeoAdd, GeoRem, GeoPos, GeoCard, GeoDist, GeoRadius, LPush, RPush, LPop, RPop, LLen, LIndex, LRange, HSet, HGet, HDel, HExists, HLen, HGetAll, Incr, CounterGet, JsonSet, JsonGet, JsonDel, BitSet, BitGet, BitCount, BitPos, HLLAdd, HLLCount, TopKAdd, TopKList, CMSIncr, CMSQuery, VAdd, VRem, VSim, VCard, VDim, VEmb, XAdd, XRange, XRevRange, XLen, XDel, XTrim.
Each keyspace has exactly one mode. Verbs that do not match the mode return invalid argument.
| Mode | Purpose | App verbs |
|---|---|---|
ModeCacheOnly |
Opaque key → []byte, no SoT |
Get, Put, Delete (+ batch) |
ModeLoadThrough |
Opaque KV + DataSource on miss |
same as CacheOnly |
ModeBloom |
Approximate membership (named filter) | BloomAdd, BloomTest; Delete(name) wipes filter |
ModeSet |
Exact membership (named set) | SetAdd, SetRemove, SetContains, SetCard, SetMembers; Delete(name) |
ModeZSet |
Scored sorted set (named zset) | ZAdd, ZRem, ZScore, ZCard, ZRange, ZRangeByScore; Delete(name) |
ModeGeo |
Named geospatial point index | GeoAdd, GeoRem, GeoPos, GeoCard, GeoDist, GeoRadius; Delete(name) |
ModeList |
Named ordered list | LPush, RPush, LPop, RPop, LLen, LIndex, LRange; Delete(name) |
ModeHash |
Named field map | HSet, HGet, HDel, HExists, HLen, HGetAll; Delete(name) |
ModeCounter |
Named int64 | Incr, CounterGet; Delete(name) |
ModeJSON |
Named nested JSON document | JsonSet, JsonGet, JsonDel; Delete(name) |
ModeBitmap |
Named packed bit vector | BitSet, BitGet, BitCount, BitPos; Delete(name) |
ModeHLL |
Named HyperLogLog sketch | HLLAdd, HLLCount; Delete(name) |
ModeTopK |
Named Space-Saving heavy-hitters | TopKAdd, TopKList; Delete(name) |
ModeCMS |
Named Count-Min frequency sketch | CMSIncr, CMSQuery; Delete(name) |
ModeVectorSet |
Named embedding set + K-NN | VAdd, VRem, VSim, VCard, VDim, VEmb; Delete(name) |
ModeStream |
Named append-only log | XAdd, XRange, XRevRange, XLen, XDel, XTrim; Delete(name) |
Config: pkg/keyspace.Config (Name, Mode, MaxBytes, TTL, ReplicationFactor, …). Bloom also uses BloomBits / BloomHashes. ModeTopK uses TopKSize (0 → 100). ModeVectorSet uses VectorDim (0 = first add locks) and VectorMetric (cosine / l2 / ip). ModeStream uses StreamMaxLen (0 = no auto-trim; hard cap 4096).
Service supercache.cache.v1.Cache on the -cache port. Full shapes: api/proto/cache.proto.
| RPC | Notes |
|---|---|
Get |
Local observation; CacheOnly miss may owner-forward |
Put / PutMany |
Owner ACK; async fan-out to R−1 replicas |
Delete / DeleteMany |
Owner tombstone + replica apply/hint |
| RPC | Notes |
|---|---|
BloomAdd |
OR bits on owner + replicas (not LWW of the bitset) |
BloomTest |
maybe=false ⇒ definitely not; missing filter ⇒ false |
Delete(name) |
Tombstone whole filter |
| RPC | Notes |
|---|---|
SetAdd / SetRemove |
Exact membership; item-level fan-out |
SetContains |
Exact; missing set ⇒ false |
SetCard / SetMembers |
Count / full members (defensive copies) |
Delete(name) |
Tombstone whole set |
| RPC | Notes |
|---|---|
ZAdd |
Upsert member score (float64; NaN rejected) |
ZRem |
Remove member if present |
ZScore |
Score + present; missing ⇒ present=false |
ZCard |
Member count |
ZRange |
By rank (Redis-style start/stop, negatives OK) |
ZRangeByScore |
Inclusive score window, ascending |
Delete(name) |
Tombstone whole zset |
Equal scores order by member bytes. Wire: ZMember { bytes member; double score }.
| RPC | Notes |
|---|---|
GeoAdd |
Upsert member lon/lat (WGS84; NaN/Inf/OOB rejected) |
GeoRem |
Remove member if present |
GeoPos |
lon + lat + present; missing ⇒ present=false |
GeoCard |
Member count |
GeoDist |
Haversine meters between two members; missing ⇒ present=false |
GeoRadius |
Points within radius_meters; nearest first; limit<=0 = all |
Delete(name) |
Tombstone whole index |
Wire: GeoMember { bytes member; double lon; double lat; double dist_meters }.
| RPC | Notes |
|---|---|
LPush / RPush |
Prepend / append; creates list if missing |
LPop / RPop |
Head / tail; missing or empty ⇒ present=false |
LLen |
Length; missing ⇒ 0 |
LIndex |
Element at index (Redis negatives); OOB ⇒ present=false |
LRange |
Inclusive window, Redis-style start/stop (-1 = last) |
Delete(name) |
Tombstone whole list |
Replicas get a full list snapshot after each owner mutate (item-level fan-out would drop earlier pushes under hint coalesce). Non-owner pop uses peer ListPop. Empty after last pop: LLen 0 until Delete(name).
| RPC | Notes |
|---|---|
HSet |
Upsert field; creates hash if missing |
HGet |
Value + present; missing hash or field ⇒ present=false |
HDel |
Remove field if present; does not Delete the name |
HExists |
Exact; missing ⇒ false |
HLen |
Field count; missing ⇒ 0 |
HGetAll |
All pairs in field-byte order (defensive copies) |
Delete(name) |
Tombstone whole hash |
Wire: HashField { bytes field; bytes value }. Item-level fan-out (FlagHashSet / FlagHashDel). Replica with a local hash does not owner-forward a field miss. Empty after last HDel: HLen 0 until Delete(name).
| RPC | Notes |
|---|---|
Incr |
Add delta (default 1 on sc); create if missing; returns new int64 |
CounterGet |
Missing ⇒ present=false, value 0 |
Delete(name) |
Tombstone whole counter |
Owner serializes Incr (non-owner uses peer CounterIncr). Replicas install an 8-byte snapshot (FlagCounter). Overflow is invalid argument (no wrap). Live 0 stays until Delete(name). Replica CounterGet may lag — Incr is authoritative.
| RPC | Notes |
|---|---|
JsonSet |
Upsert JSON at path; creates the document if missing |
JsonGet |
JSON + present; missing doc or path ⇒ present=false. Path $ or omitted = whole document |
JsonDel |
Remove node at path. $ / omitted clears to live {}. Missing path is a no-op |
Delete(name) |
Tombstone whole document |
Path subset: $ / .ident / ["utf8"] / [n>=0]. Object parents are created; arrays are not. Integers stay integers (UseNumber). Live JSON null is present; a missing name is not. Replicas install a full document snapshot (FlagJSON). Replica JsonGet may lag.
| RPC | Notes |
|---|---|
BitSet |
Redis SETBIT. Creates the bitmap if missing; grows with zero-fill. ACK-only — does not return the old bit |
BitGet |
Redis GETBIT plus a present-bit. Missing name ⇒ present=false. Live bitmap, offset past stored length ⇒ bit=false, present=true |
BitCount |
Redis BITCOUNT over an inclusive byte window. Missing name ⇒ 0. Whole bitmap is start=0, end=-1 |
BitPos |
Redis BITPOS over an inclusive byte window (stored bytes only). Missing name or bit not in window ⇒ found=false |
Delete(name) |
Tombstone whole bitmap |
Bit 0 is the MSB of byte 0 (Redis order, not Bloom LSB). Clearing bits (BitSet(..., false)) is not a delete: a live all-zero bitmap stays until Delete(name), and the stored byte length never shrinks. Replicas install a full packed snapshot (FlagBitmap). Replica BitGet may lag. Get/Put on ModeBitmap are invalid.
| RPC | Notes |
|---|---|
HLLAdd |
Redis PFADD. Creates the sketch if missing. ACK-only — does not return whether any register changed |
HLLCount |
Approximate distinct count plus a present-bit. Missing name ⇒ present=false. Live sketch (including estimate 0) ⇒ present=true |
Delete(name) |
Tombstone whole sketch |
One named sketch, FNV-1a 64, p=14, dense 12 KiB. Items are hashed, not stored. Empty item is invalid. Estimates will not match Redis PFCOUNT (different hash, no sparse/bias tables). Replicas install a full register snapshot (FlagHLL). Replica HLLCount may lag. Get/Put on ModeHLL are invalid. PFMERGE is not v1.
| RPC | Notes |
|---|---|
TopKAdd |
Observe item once (+1). Creates the table if missing. ACK-only |
TopKList |
Current chart (count desc, then item bytes). Missing name ⇒ present=false. Live table ⇒ present=true |
Delete(name) |
Tombstone whole table |
Named Space-Saving table. Writes are observations, not scores (ZAdd is the exact scored set). Memory is O(K) (TopKSize, default 100). Empty item is invalid. Replicas install a full FlagTopK snapshot. Replica TopKList may lag. Get/Put on ModeTopK are invalid. Not Redis TOPK (different algorithm; no Query/Count/Incr in v1). Live billboard: examples/billboard.
| RPC | Notes |
|---|---|
CMSIncr |
Observe item n times (n==0 means 1). Creates the sketch if missing. ACK-only (does not return the new estimate) |
CMSQuery |
Min of d cells. Missing name ⇒ present=false. Live sketch ⇒ present=true |
Delete(name) |
Tombstone whole sketch |
Named Count-Min Sketch. Items are hashed, not stored. Fixed 64 KiB (d=4, w=2048). Empty item is invalid. Replicas install a full FlagCMS snapshot. Replica CMSQuery may lag. Get/Put on ModeCMS are invalid. Not Redis CMS.* (different hash; no merge). Billboard complement: examples/billboard plays-count.
Hosted shapes: Cache gRPC tab on /docs (VAdd … VEmb).
| RPC | Notes |
|---|---|
VAdd |
Upsert member → []float32. Creates the set if missing. ACK-only. First add locks dim |
VRem |
Remove member if present. Last rem keeps an empty live set (dim still present) |
VSim |
Brute-force top-k (k≤0 → 10, k>50 → 50). Missing name → empty hits. Best first |
VCard |
Member count. Missing name ⇒ present=false. Empty live set ⇒ present=true, n=0 |
VDim |
Locked dim. Missing name ⇒ present=false. Empty live set still reports dim |
VEmb |
Stored vector copy. Missing name/member ⇒ found=false |
Delete(name) |
Tombstone whole set |
Named embedding set. Dim 2–256, max 512 members, member id 1–255 bytes. Keyspace VectorMetric: cosine (default, high→low; rejects zero), l2 (low→high), ip (high→low). Replicas install a full FlagVectorSet snapshot. Replica VSim may lag. Get/Put on ModeVectorSet are invalid. Not HNSW / not Redis VADD wire. Walkthrough: examples/vecset. CLI: sc -keyspace vectorset vadd items a 1,0.
| RPC | Notes |
|---|---|
XAdd |
Append opaque []byte. Creates the stream if missing. Returns minted id millis-seq |
XRange |
Inclusive id window, oldest first. - / +. Start (+id is exclusive. Missing → empty |
XRevRange |
Same start/end window as XRange, newest first |
XLen |
Count + present-bit. Missing ⇒ present=false |
XDel |
Remove one id. ACK-only. Missing id is a no-op |
XTrim |
Keep newest max_len. ACK-only |
Delete(name) |
Tombstone whole stream |
Named append-only log. Payload is opaque (client encodes). Owner mints ids; XAdd from a non-owner uses peer StreamAdd. Replicas install a full FlagStream snapshot. StreamMaxLen 0 = no auto-trim; hard cap 4096. Empty after last delete/trim stays live until Delete(name). Get/Put invalid. Not consumer groups / not blocking XREAD. CLI: sc -keyspace events xadd logs * hello.
- Repo Settings → Pages → Build and deployment → GitHub Actions
- Push to
main(workflow.github/workflows/docs.yml) - Site URL:
https://<owner>.github.io/supercache/
The workflow copies OpenAPI + UI from source into the Pages artifact so the site stays aligned with the embedded node docs.