README
- Mention social feed in the one-line description and feature bullets
- Add relay + feed endpoint tables to the API overview (was
previously empty on messaging)
- List media/ package in the repo structure
docs/api/
- New docs/api/feed.md: full reference for /feed/publish, fetch,
stats, view, author, timeline, trending, foryou, hashtag; all
on-chain CREATE_POST / DELETE_POST / FOLLOW / LIKE payloads;
fee economics; server-side scrubbing contract.
- docs/api/relay.md rewritten: /relay/broadcast is now the primary
E2E path with a complete envelope schema; /relay/send kept but
flagged ⚠ NOT E2E; DELETE /relay/inbox/{id} documented with the
new Ed25519 signed-auth body.
- docs/api/README.md index: added feed.md row.
docs/architecture.md
- L2 Transport layer description updated to include the feed
mailbox alongside the 1:1 relay mailbox.
- New "Социальная лента (v2.0.0)" section right after the 1:1
message flow: ASCII diagram of publish + on-chain commit +
timeline fetch, economic summary, metadata-scrub summary.
docs/node/README.md
- Removed stale chan:/chan-member: keys from the BadgerDB schema
reference; replaced with the v2.0.0 feed keys (post:,
postbyauthor:, follow:, followin:, like:, likecount:).
docs/update-system.md
- Example features[] array updated to match the actual node output
(channels_v1 removed, feed_v2 / media_scrub / relay_broadcast added).
Node feature flags
- api_well_known_version.go: dropped channels_v1 tag (the
/api/channels/:id endpoint was removed in the feed refactor);
added feed_v2, media_scrub, relay_broadcast so clients can
feature-detect the v2.0.0 surface.
- Comment example updated channels_v2/v1 → feed_v3/v2.
Client
- CLIENT_REQUIRED_FEATURES expanded to include the v2.0.0 feature
flags the client now depends on (feed_v2, media_scrub,
relay_broadcast); checkNodeVersion() will flag older nodes as
unsupported and surface an upgrade prompt.
All 7 Go test packages green; tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
3.7 KiB
Go
96 lines
3.7 KiB
Go
// Package node — /api/well-known-version endpoint.
|
|
//
|
|
// Clients hit this to feature-detect the node they're talking to, without
|
|
// hardcoding "node >= 0.5 supports channels" into every screen. The response
|
|
// lists three coordinates a client cares about:
|
|
//
|
|
// - node_version — human-readable build tag (ldflags-injectable)
|
|
// - protocol_version — integer bumped only on wire-protocol breaking changes
|
|
// - features — stable string tags for "this binary implements X"
|
|
//
|
|
// Feature tags are ADDITIVE — once a tag ships in a release, it keeps being
|
|
// returned forever (even if the implementation moves around internally). The
|
|
// client uses them as "is this feature here or not?", not "what version is
|
|
// this feature at?". Versioning a feature is done by shipping a new tag
|
|
// (e.g. "feed_v3" alongside "feed_v2" for a deprecation window).
|
|
//
|
|
// Response shape:
|
|
//
|
|
// {
|
|
// "node_version": "0.5.0-dev",
|
|
// "protocol_version": 1,
|
|
// "features": [
|
|
// "channels_v1",
|
|
// "fan_out",
|
|
// "native_username_registry",
|
|
// "ws_submit_tx",
|
|
// "access_token"
|
|
// ],
|
|
// "chain_id": "dchain-ddb9a7e37fc8"
|
|
// }
|
|
package node
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"sort"
|
|
|
|
"go-blockchain/node/version"
|
|
)
|
|
|
|
// ProtocolVersion is bumped only when the wire-protocol changes in a way
|
|
// that a client compiled against version N cannot talk to a node at
|
|
// version N+1 (or vice versa) without updating. Adding new optional fields,
|
|
// new EventTypes, new WS ops, new HTTP endpoints — none of those bump this.
|
|
//
|
|
// Bumping this means a coordinated release: every client and every node
|
|
// operator must update before the old version stops working.
|
|
const ProtocolVersion = 1
|
|
|
|
// nodeFeatures is the baked-in list of feature tags this binary implements.
|
|
// Append-only. When you add a new tag, add it here AND document what it means
|
|
// so clients can feature-detect reliably.
|
|
//
|
|
// Naming convention: snake_case, versioned suffix for anything that might get
|
|
// a breaking successor (e.g. `channels_v1`, not `channels`).
|
|
var nodeFeatures = []string{
|
|
"access_token", // DCHAIN_API_TOKEN gating on writes (+ optional reads)
|
|
"chain_id", // /api/network-info returns chain_id
|
|
"contract_logs", // /api/contract/:id/logs endpoint
|
|
"fan_out", // client-side per-recipient envelope sealing
|
|
"feed_v2", // social feed: posts, likes, follows, timeline, trending, for-you
|
|
"identity_registry", // /api/identity/:pub returns X25519 pub + relay hints
|
|
"media_scrub", // mandatory EXIF/GPS strip on /feed/publish
|
|
"native_username_registry", // native:username_registry contract
|
|
"onboarding_api", // /api/network-info for joiner bootstrap
|
|
"payment_channels", // off-chain payment channel open/close
|
|
"relay_broadcast", // /relay/broadcast (E2E envelope publish)
|
|
"relay_mailbox", // /relay/inbox (read), /relay/send (legacy non-E2E)
|
|
"ws_submit_tx", // WebSocket submit_tx op
|
|
}
|
|
|
|
func registerWellKnownVersionAPI(mux *http.ServeMux, q ExplorerQuery) {
|
|
mux.HandleFunc("/api/well-known-version", func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
jsonErr(w, fmt.Errorf("method not allowed"), 405)
|
|
return
|
|
}
|
|
// Return a copy so callers can't mutate the shared slice.
|
|
feats := make([]string, len(nodeFeatures))
|
|
copy(feats, nodeFeatures)
|
|
sort.Strings(feats)
|
|
|
|
resp := map[string]any{
|
|
"node_version": version.Tag,
|
|
"build": version.Info(),
|
|
"protocol_version": ProtocolVersion,
|
|
"features": feats,
|
|
}
|
|
// Include chain_id if the node exposes it (same helper as network-info).
|
|
if q.ChainID != nil {
|
|
resp["chain_id"] = q.ChainID()
|
|
}
|
|
jsonOK(w, resp)
|
|
})
|
|
}
|