Home How it works
NOSISTER

How nosister works

nosister is an Issuer-Specified Expiry (ISE) Nostr relay: publishers can set their own event lifetime using an ["expiration","<unix>"] tag, and the relay also honors issuer delete events.

Supported Nostr features

  • The relay accepts standard EVENT, REQ, and CLOSE commands over WebSocket.
  • Event validation checks schema, computed event hash, signature, event-size limits, and REQ filter complexity limits.
  • There is no kind allowlist in the relay write path: any valid kind can be persisted.
  • The homepage LiveFeed only subscribes to a selected kind set:
    1, 20, 6, 7, 3, 10002, 14, 5, 9734, 9735, 30023, 30000, 30402.

So: relay storage is broader than what the homepage feed displays.

Issuer-Specified Expiry (ISE)

Non-standard note: ISE is a nosister relay policy built on top of the standard NIP-40 expiration tag handling.

  • On insert, nosister reads the first event tag whose name is exactly "expiration".
  • If present, value parsing order is: numeric Unix seconds first; then a Date.parse fallback.
  • If parsing succeeds, that timestamp is written to events.expires_at; if not, expires_at is NULL.
  • Read/query paths return only rows where deleted_at IS NULL and (expires_at IS NULL OR expires_at > NOW()).
  • The relay does not clamp or override requested expiration based on account plan in current code.

What happens in edge cases?

  • No expiration tag: expires_at stays NULL (archival by default).
  • Malformed expiration tag: parse fails, so expires_at becomes NULL.
  • Expiration in the past: event can still be inserted, but historical REQ queries immediately filter it out as expired.

Example: kind 1 with ~24h expiry

{
  "kind": 1,
  "content": "Hello from nosister with 24h expiry",
  "tags": [["expiration", "1735862400"]]
}

Example: kind 1 with ~30 day expiry

{
  "kind": 1,
  "content": "Longer-lived note (~30 days)",
  "tags": [["expiration", "1738368000"]]
}
If you omit ["expiration", "..."], current relay behavior is indefinite retention unless later deleted by issuer (kind 5) or removed by operator action.

Relay behavior & policies

  • Rate limiting: per-IP concurrent connection cap and per-IP message-rate window are enforced; over-limit clients get NOTICE and socket close.
  • Blocking: blocked IPs are rejected at connection preflight; blocked pubkeys can connect but their events are rejected with NOTICE + OK false.
  • Deletion: kind 5 events are applied to issuer-owned target ids and set deleted_at in storage.
  • Plan limits: plans enforce per-pubkey daily event and byte quotas on publish. This does not alter event expires_at semantics.

Protocol responses used by nosister

  • OK: sent for each EVENT publish attempt (accepted or rejected).
  • NOTICE: sent for malformed commands, policy violations, or rate-limit rejections.
  • EOSE: sent after stored historical events are replayed to a new subscription.

HTTP introspection endpoints

  • GET /policy → retention policy object (mode, summary, fields).
  • GET /relay-info (and / with Accept: application/nostr+json) → relay metadata, supported NIPs, retention summary.
  • GET /health → status + DB up/down + retention mode.

Using nosister in practice

With nosterize

  1. Add wss://relay.nosister.com to your relay set.
  2. Create/sign an event (for ISE, include ["expiration", "<unix>"] in tags).
  3. Publish and expect NIP-20 ["OK","<eventid>",true,""] on acceptance.

With wscat / raw WebSocket

wscat -c wss://relay.nosister.com
["EVENT",{
  "id":"<event-id>",
  "pubkey":"<hex-pubkey>",
  "created_at":1735776000,
  "kind":1,
  "tags":[["expiration","1735862400"]],
  "content":"hello nosister",
  "sig":"<signature>"
}]
["OK","<event-id>",true,""]

With Nostr clients

Any client that can publish to normal relays can use nosister. ISE is opt-in: add an expiration tag when you want timed expiry.

How the homepage LiveFeed works

  • The homepage opens a WebSocket to wss://relay.nosister.com.
  • It sends a REQ with the tracked kind list and since = now - 30 minutes.
  • Event counters, activity bars, and the event list are derived from the same relay messages normal clients receive (EVENT / EOSE stream behavior).

The UI can optionally hide content but still shows metadata.