Back to Atlas map viewer
SOURCE / PINNED RELEASE

Made of little things.

Atlas map viewer

Release
1d2807e80b44…
Author-recorded commit
43810ed2b368…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-4757dbabc86

Archive hash verified: 8db6876d96c460ac…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

app/src/signed-map-library.ts
import { verifyEvent, type Event } from 'nostr-tools/pure';
import { MAP_KIND, parseAnnouncement } from '../../packages/hashtree/src/announcement';
import { HASH, parseFipsProviders } from '../../packages/hashtree/src/offer';
import { VIEW_KIND, parseViewAnnouncement } from '../../packages/views/src/announcement';
import type { MapOffer } from '../../packages/format/src/catalog';
import {
  parseConsumerConfig,
  type ConsumerConfig,
  type ConsumerStatus,
} from './discovery-contract';
export type Entry = { offer: MapOffer; event: Event; abort: AbortController; expires: number };
const newer = (next: Event, old?: Event) =>
  !old ||
  next.created_at > old.created_at ||
  (next.created_at === old.created_at && next.id < old.id);
const cancelled = () => new DOMException('Map offer was superseded or withdrawn', 'AbortError');
/** Atlas semantics only: no relay pool, FIPS connection or shell authority. */
export class SignedMapLibrary {
  readonly config: ConsumerConfig;
  private lifetime = new AbortController();
  private entries = new Map<string, Entry>();
  private revisions = new Map<string, Event>();
  private withdrawals = new Map<string, number>();
  private deleted = new Set<string>();
  private views = new Map<
    string,
    ReturnType<typeof parseViewAnnouncement> & { expires?: number }
  >();
  private viewRevisions = new Map<string, Event>();
  private expiryTimer?: ReturnType<typeof setTimeout>;
  private error?: string;
  constructor(
    config: ConsumerConfig,
    private changed: () => void = () => {},
  ) {
    this.config = parseConsumerConfig(config);
  }
  private emit(_kind: 'catalog') {
    this.changed();
  }
  accept(event: unknown) {
    const kind = (event as Event)?.kind;
    return kind === 5
      ? this.acceptDeletion(event)
      : kind === VIEW_KIND
        ? this.acceptView(event)
        : this.acceptAnnouncement(event);
  }
  catalog(): Pick<ConsumerStatus, 'catalog' | 'defaultView' | 'preferredMapIds'> {
    this.expire();
    const catalog = [...this.entries.values()]
      .map(({ offer, event }) => ({
        key: `${event.pubkey}:${offer.id}@${offer.hashtree!.root}`,
        offer,
        publisher: event.pubkey,
      }))
      .sort((a, b) => a.key.localeCompare(b.key));
    const roots = new Set(catalog.map((entry) => entry.offer.hashtree!.root));
    const view = [...this.views.values()]
      .sort(
        (a, b) => b.event.created_at - a.event.created_at || a.event.id.localeCompare(b.event.id),
      )
      .find((v) => v.recipe.sources.every((source) => roots.has(source.root)));
    return structuredClone({
      catalog,
      ...(view ? { defaultView: view.recipe } : {}),
      preferredMapIds: this.config.mapIds ?? [],
    });
  }
  acceptAnnouncement(raw: unknown): boolean {
    if (this.lifetime.signal.aborted) return false;
    let rejectedRevision: string | undefined;
    try {
      const { event, offer } = parseAnnouncement(raw);
      if (event.pubkey !== this.config.publisher || !offer.hashtree) return false;
      const address = `${event.pubkey}:${offer.id}`;
      if (
        !newer(event, this.revisions.get(address)) ||
        (this.withdrawals.get(address) ?? -1) >= event.created_at ||
        this.deleted.has(`${event.pubkey}:${event.id}`)
      )
        return false;
      if (!this.revisions.has(address) && this.revisions.size >= 4096) return false;
      this.revisions.set(address, event);
      rejectedRevision = address;
      const fips = parseFipsProviders(offer.hashtree.fips);
      if (!fips.length) throw new Error('Signed map does not advertise FIPS providers');
      for (const provider of fips) {
        if (
          provider.servicePort !== 39018 ||
          (provider.rpcPort !== undefined && provider.rpcPort !== 39019)
        )
          throw new Error('Unsupported signed FIPS service port');
        for (const seed of provider.seedUrls) {
          const url = new URL(seed);
          if (url.protocol === 'ws:' && !['localhost', '127.0.0.1', '[::1]'].includes(url.hostname))
            throw new Error('Unencrypted FIPS seeds must be loopback');
        }
      }
      const root = offer.hashtree.root;
      const previous = this.entries.get(address);
      previous?.abort.abort(cancelled());
      // Signed HTTP hints are intentionally absent from the consumer contract.
      const safe: MapOffer = {
        id: offer.id,
        url: `htree://${offer.hashtree.root}`,
        bytes: offer.bytes,
        manifest: offer.manifest,
        hashtree: { ...offer.hashtree, providers: [], fips },
      };
      this.entries.set(address, {
        offer: safe,
        event,
        abort: new AbortController(),
        expires: Number(event.tags.find((tag) => tag[0] === 'expiration')![1]),
      });

      this.error = undefined;
      rejectedRevision = undefined;
      this.scheduleExpiry();
      this.emit('catalog');
      return true;
    } catch {
      // A newer valid signed revision supersedes an older offer even if its transport is unsupported.
      if (rejectedRevision) {
        this.remove(rejectedRevision);
        this.scheduleExpiry();
        this.emit('catalog');
      }
      return false;
    }
  }
  acceptView(raw: unknown): boolean {
    if (this.lifetime.signal.aborted) return false;
    try {
      const parsed = parseViewAnnouncement(raw, this.config.publisher),
        key = `view:${parsed.event.pubkey}:${parsed.recipe.id}`;
      if (
        !newer(parsed.event, this.viewRevisions.get(key)) ||
        (this.withdrawals.get(key) ?? -1) >= parsed.event.created_at ||
        this.deleted.has(`${parsed.event.pubkey}:${parsed.event.id}`) ||
        (this.viewRevisions.size >= 128 && !this.viewRevisions.has(key))
      )
        return false;
      const expiration = parsed.event.tags.filter((tag) => tag[0] === 'expiration');
      const expires = expiration.length ? Number(expiration[0]![1]) : undefined;
      this.viewRevisions.set(key, parsed.event);
      if (
        expiration.length > 1 ||
        (expires !== undefined && (!Number.isSafeInteger(expires) || expires <= Date.now() / 1000))
      ) {
        this.views.delete(key);
        this.scheduleExpiry();
        this.emit('catalog');
        return false;
      }
      this.views.set(key, { ...parsed, expires });
      this.scheduleExpiry();
      this.emit('catalog');
      return true;
    } catch {
      return false;
    }
  }
  acceptDeletion(raw: unknown): boolean {
    if (this.lifetime.signal.aborted) return false;
    try {
      if (JSON.stringify(raw).length > 256 * 1024) return false;
      const event = JSON.parse(JSON.stringify(raw)) as Event;
      if (
        event.kind !== 5 ||
        event.pubkey !== this.config.publisher ||
        !verifyEvent(event) ||
        event.created_at > Math.floor(Date.now() / 1000) + 300
      )
        return false;
      for (const tag of event.tags) {
        const prefix = `${MAP_KIND}:${event.pubkey}:atlas/`;
        if (tag[0] === 'a' && tag[1]?.startsWith(prefix)) {
          const address = `${event.pubkey}:${tag[1].slice(prefix.length)}`;
          this.withdrawals.set(
            address,
            Math.max(event.created_at, this.withdrawals.get(address) ?? -1),
          );
          const entry = this.entries.get(address);
          if (entry && entry.event.created_at <= event.created_at) this.remove(address);
        } else if (
          tag[0] === 'a' &&
          tag[1]?.startsWith(`${VIEW_KIND}:${event.pubkey}:atlas-view/`)
        ) {
          const address = `view:${event.pubkey}:${tag[1].slice(`${VIEW_KIND}:${event.pubkey}:atlas-view/`.length)}`;
          this.withdrawals.set(
            address,
            Math.max(event.created_at, this.withdrawals.get(address) ?? -1),
          );
          const view = this.views.get(address);
          if (view && view.event.created_at <= event.created_at) this.views.delete(address);
        } else if (tag[0] === 'e' && HASH.test(tag[1] ?? '')) {
          this.deleted.add(`${event.pubkey}:${tag[1]}`);
          for (const [address, entry] of this.entries)
            if (entry.event.id === tag[1] && entry.event.created_at <= event.created_at)
              this.remove(address);
          for (const [address, view] of this.views)
            if (view.event.id === tag[1] && view.event.created_at <= event.created_at)
              this.views.delete(address);
        }
      }
      this.scheduleExpiry();
      this.emit('catalog');
      return true;
    } catch {
      return false;
    }
  }
  private remove(address: string) {
    const old = this.entries.get(address);
    if (!old) return;
    old.abort.abort(cancelled());
    this.entries.delete(address);
  }
  private expire() {
    let changed = false;
    for (const [address, entry] of this.entries)
      if (entry.expires <= Date.now() / 1000) {
        this.remove(address);
        changed = true;
      }
    for (const [address, view] of this.views)
      if (view.expires !== undefined && view.expires <= Date.now() / 1000) {
        this.views.delete(address);
        changed = true;
      }
    if (changed) {
      this.scheduleExpiry();
      this.emit('catalog');
    }
  }
  private scheduleExpiry() {
    clearTimeout(this.expiryTimer);
    const deadlines = [...this.entries.values()]
      .map((entry) => entry.expires)
      .concat(
        [...this.views.values()].flatMap((view) =>
          view.expires === undefined ? [] : [view.expires],
        ),
      );
    if (!deadlines.length) return;
    const next = Math.min(...deadlines);
    this.expiryTimer = setTimeout(
      () => {
        this.expire();
        this.scheduleExpiry();
      },
      Math.min(2147483647, Math.max(1, next * 1000 - Date.now())),
    );
  }
  entry(root: string): Entry {
    this.lifetime.signal.throwIfAborted();
    this.expire();
    if (typeof root !== 'string' || !HASH.test(root)) throw new Error('Invalid pinned map root');
    const entry = [...this.entries.values()].find((e) => e.offer.hashtree!.root === root);
    if (!entry) throw new Error('Map root is not in the active signed catalog');
    return entry;
  }

  close() {
    if (this.lifetime.signal.aborted) return;
    this.lifetime.abort(cancelled());
    clearTimeout(this.expiryTimer);
    for (const entry of this.entries.values()) entry.abort.abort(cancelled());
    this.entries.clear();
    this.views.clear();
    this.revisions.clear();
    this.viewRevisions.clear();
    this.withdrawals.clear();
    this.deleted.clear();
  }
}