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.

packages/format/src/index.ts
import {
  validateTransportMetadata,
  type RoutingFederation,
} from "./routing-contract";
import {
  validateComposition,
  MEMBER_CHUNK_BYTES,
  type ArchiveComposition,
} from "./composition-schema";
import { validateFamilies, type DataFamily } from "./families";
import { validateRasters, type RasterLayer } from "./raster";
import { pagedZoom } from "../../geocoding/src/paging";
/** ATLAS v0.1: immutable single-file package with independently addressed blocks. */
export const MAGIC = "ATLAS001";
export const HEADER_SIZE = 32;
export const TILE_EXTENT = 65535;
export const MAP_LAYERS = [
  "land",
  "water",
  "buildings",
  "roads",
  "railways",
  "peaks",
] as const;
export type MapLayer = (typeof MAP_LAYERS)[number];
export const LAYER_MASKS: Record<MapLayer, number> = {
  land: 1,
  water: 2,
  buildings: 4,
  roads: 56,
  railways: 64,
  peaks: 128,
};
export function layerForClass(cls: number): MapLayer {
  const layer = [
    "land",
    "water",
    "buildings",
    "roads",
    "roads",
    "roads",
    "railways",
    "peaks",
  ][cls];
  if (!layer) throw new Error("Invalid tile class");
  return layer as MapLayer;
}
export function tileLayer(key: string): MapLayer | undefined {
  const layer = key.split("/")[1];
  return key.startsWith("tile/") && MAP_LAYERS.includes(layer as MapLayer)
    ? (layer as MapLayer)
    : undefined;
}
export function isTilePrefix(prefix: string) {
  return prefix === "tile" || prefix.startsWith("tile/");
}
export const MAX_METADATA = 64 * 1024 * 1024;
export interface Peak {
  id: string;
  name: string;
  coordinates: [number, number];
  elevation: number | null;
}
export interface Place {
  name: string;
  coordinates: [number, number];
}
export const TRANSPORT_MODES = ["walking", "cycling", "driving"] as const;
export type TransportMode = (typeof TRANSPORT_MODES)[number];
export interface TransportProfile {
  prefix: string;
  zoom: 14;
  count: number;
  codec: "rcl2" | "rcl3";
  nodes: number;
  segments: number;
  turns: number;
  skippedWays: number;
  unsupportedRestrictions: number;
  excludedRestrictionWays: number;
}
export interface TransportMetadata {
  version: 1;
  /** Identity of the compiled graph whose cells are copied unchanged into excerpts. */
  graphSnapshot?: string;
  federation?: RoutingFederation;
  profiles: Partial<Record<TransportMode, TransportProfile>>;
  statistics?: "cell-records";
}
export function isRoutingCell(key: string) {
  return /^routing\/(?:walking\/|cycling\/|driving\/)?cells\//.test(key);
}
function routingZoom(manifest: Manifest, prefix: string) {
  return prefix === "routing/cells"
    ? manifest.routing?.cells?.zoom
    : Object.values(manifest.transport?.profiles ?? {}).find(
        (p) => p.prefix === prefix,
      )?.zoom;
}
export interface RoutingMetadata {
  cells?: { zoom: 14; count: number; codec: "rcl1" };
  profile: "walking-v1";
  block: "routing/walking";
  nodes: number;
  segments: number;
  bytes: number;
  skippedWays: number;
  snapLimitMeters: 150;
  scope: "retained-source-extract";
}
export interface Manifest {
  format: "atlas";
  version: 1;
  name: string;
  source: {
    url: string;
    sha256: string;
    attribution: string;
    inputs?: Array<{ url: string; sha256: string; bytes: number }>;
    extraction?: { bounds: number[]; strategy: string; sourceDate: string };
  };
  bounds: [number, number, number, number];
  minZoom: number;
  maxZoom: number;
  features: number;
  peaks: number;
  places: Place[];
  capabilities: string[];
  limitations: string[];
  snapshot: string;
  routing?: RoutingMetadata;
  transport?: TransportMetadata;
  labelZoom?: number;
  featureZoom?: number;
  /** Version 2 separates bounded attributes and geometry pages within the archive. */
  featureSchema?: 2;
  featureKinds?: (
    | "buildings"
    | "water"
    | "railways"
    | "roads"
    | "land"
    | "boundaries"
    | "objects"
  )[];
  tileLayers?: MapLayer[];
  rasters?: RasterLayer[];
  families?: DataFamily[];
  composition?: ArchiveComposition;
  buildingHeights?: {
    tagged: number;
    estimated: number;
    missing: number;
    maxMeters: number;
  };
  areas?: { assembledRelations: number; skippedRelations: number };
  featureCountKind?: "tile-records";
  semantics?: {
    version: 1;
    addresses: "osm-explicit";
    poiTags: boolean;
    administrativeHierarchy: boolean;
  };
  /** Immutable revision lineage; payload families remain self-contained. */
  amendment?: {
    version: 1;
    parentSnapshot: string;
    sourceSnapshot: string;
    builder: string;
    addedFamilies: string[];
    routingPaddingCells: number;
  };
  selection?: {
    polygon: [number, number][];
    parentSnapshot: string;
    boundaryPolicy: string;
    routingPaddingCells?: number;
  };
}
export interface Block {
  key: string;
  offset: number;
  length: number;
  hash: string;
  features: number;
  codec?: "gzip";
  rawLength?: number;
  z?: number;
  x?: number;
  y?: number;
}
export const INDEX_PAGE_SIZE = 32;
export function spatialAddress(key: string) {
  const label =
    /^labels\/(\d+)\/(\d+)\/(\d+)\/(roads|pois)\/(13|14|15|16|17)$/.exec(key);
  if (label)
    return {
      prefix: `labels/${label[4]}/${label[5]}`,
      z: Number(label[1]),
      x: Number(label[2]),
      y: Number(label[3]),
    };
  const m =
    /^(tile(?:\/(?:land|water|buildings|roads|railways|peaks))?|members\/m[0-9]{1,3}|raster\/[a-z][a-z0-9_-]{0,63}|features\/(?:buildings|water|railways|roads|land|attributes|geometry)|boundaries\/(?:records|geometry)|objects\/(?:geometry|topology|records|spatial|ids|lookup|tag-values|tag-index|tag-pages)|search\/(?:records|postings|terms|streets-data|locations-data|location-pages|street-pages)|labels\/settlements|query\/peaks-data|routing\/(?:(?:walking|cycling|driving)\/)?cells)\/(\d+)\/(\d+)\/(\d+)$/.exec(
      key,
    );
  return m
    ? { prefix: m[1]!, z: Number(m[2]), x: Number(m[3]), y: Number(m[4]) }
    : null;
}
export function pageKey(prefix: string, z: number, x: number, y: number) {
  return `index/${prefix === "tile" ? "tiles" : prefix}/${z}/${x}/${y}`;
}
export interface IndexPage extends Block {
  prefix?: string;
  z: number;
  x: number;
  y: number;
  count: number;
}
export interface Header {
  version: 1 | 2;
  manifestLength: number;
  directoryLength: number;
  payloadOffset: number;
  fileLength: number;
}
export interface PackageIndex {
  header: Header;
  manifest: Manifest;
  /** Root entries only in v2. Use reader.tiles() or reader.allBlocks(). */
  blocks: Block[];
  pages: IndexPage[];
  /** Display blocks; a spatial tile can have multiple independently stored layers. */
  tileCount: number;
  blockCount: number;
}
const decoder = new TextDecoder();
export function parseHeader(bytes: Uint8Array): Header {
  if (
    bytes.byteLength !== HEADER_SIZE ||
    decoder.decode(bytes.subarray(0, 8)) !== MAGIC
  )
    throw new Error("Not an ATLAS package");
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
  if (![1, 2].includes(view.getUint32(8, true)))
    throw new Error("Unsupported ATLAS version");
  const header: Header = {
    version: view.getUint32(8, true) as 1 | 2,
    manifestLength: view.getUint32(12, true),
    directoryLength: view.getUint32(16, true),
    payloadOffset: view.getUint32(20, true),
    fileLength: Number(view.getBigUint64(24, true)),
  };
  if (
    header.manifestLength + header.directoryLength > MAX_METADATA ||
    header.payloadOffset !==
      HEADER_SIZE + header.manifestLength + header.directoryLength ||
    !Number.isSafeInteger(header.fileLength) ||
    header.fileLength < header.payloadOffset
  )
    throw new Error("Invalid ATLAS header bounds");
  return header;
}
export function parseIndex(header: Header, bytes: Uint8Array): PackageIndex {
  if (bytes.length !== header.payloadOffset - HEADER_SIZE)
    throw new Error("Truncated ATLAS index");
  const manifest = JSON.parse(
    decoder.decode(bytes.subarray(0, header.manifestLength)),
  ) as Manifest;
  const directory = JSON.parse(
    decoder.decode(bytes.subarray(header.manifestLength)),
  );
  const blocks: Block[] = header.version === 1 ? directory : directory.blocks;
  const pages: IndexPage[] = header.version === 1 ? [] : directory.pages;
  if (!Array.isArray(pages)) throw new Error("Invalid ATLAS directory pages");
  if (
    manifest.format !== "atlas" ||
    manifest.version !== 1 ||
    typeof manifest.name !== "string" ||
    !Array.isArray(manifest.bounds) ||
    manifest.bounds.length !== 4 ||
    !manifest.bounds.every(Number.isFinite) ||
    !Number.isInteger(manifest.minZoom) ||
    !Number.isInteger(manifest.maxZoom) ||
    manifest.minZoom < 0 ||
    manifest.maxZoom > 18 ||
    manifest.minZoom > manifest.maxZoom ||
    !Array.isArray(manifest.places) ||
    !Array.isArray(manifest.capabilities) ||
    !Array.isArray(blocks)
  )
    throw new Error("Invalid ATLAS manifest");
  if (
    typeof manifest.snapshot !== "string" ||
    !/^[a-f0-9]{64}$/.test(manifest.snapshot) ||
    !Number.isSafeInteger(manifest.features) ||
    manifest.features < 0 ||
    !Number.isSafeInteger(manifest.peaks) ||
    manifest.peaks < 0 ||
    !manifest.capabilities.every((c) => typeof c === "string") ||
    !manifest.places.every(
      (p) =>
        p &&
        typeof p.name === "string" &&
        Array.isArray(p.coordinates) &&
        p.coordinates.length === 2 &&
        p.coordinates.every(Number.isFinite),
    ) ||
    manifest.bounds[0] >= manifest.bounds[2] ||
    manifest.bounds[1] >= manifest.bounds[3] ||
    manifest.bounds[0] < -180 ||
    manifest.bounds[2] > 180 ||
    manifest.bounds[1] < -90 ||
    manifest.bounds[3] > 90
  )
    throw new Error("Invalid ATLAS metadata");
  if (
    manifest.tileLayers !== undefined &&
    (!Array.isArray(manifest.tileLayers) ||
      manifest.tileLayers.some((l) => !MAP_LAYERS.includes(l)) ||
      new Set(manifest.tileLayers).size !== manifest.tileLayers.length)
  )
    throw new Error("Invalid map layer catalog");
  validateComposition(manifest.composition);
  if (
    manifest.capabilities.includes("map-composition") !== !!manifest.composition
  )
    throw new Error("Composition capability mismatch");
  validateRasters(manifest.rasters);
  validateFamilies(manifest.families);
  if (
    manifest.capabilities.includes("raster-rendering") !==
    !!manifest.rasters?.length
  )
    throw new Error("Raster capability mismatch");
  if (manifest.buildingHeights) {
    const h = manifest.buildingHeights;
    if (
      ![h.tagged, h.estimated, h.missing].every(
        (n) => Number.isSafeInteger(n) && n >= 0,
      ) ||
      !Number.isFinite(h.maxMeters) ||
      h.maxMeters < 0 ||
      h.maxMeters > 2000
    )
      throw new Error("Invalid building height metadata");
  }
  if (manifest.capabilities.includes("map-labels") && manifest.labelZoom !== 12)
    throw new Error("Invalid label grid");
  if (
    manifest.capabilities.includes("feature-extraction") &&
    manifest.featureZoom !== 12
  )
    throw new Error("Invalid feature grid");
  if (
    manifest.featureSchema !== undefined &&
    (manifest.featureSchema !== 2 ||
      !manifest.capabilities.includes("feature-extraction"))
  )
    throw new Error("Invalid feature schema");
  if (manifest.amendment) {
    const a = manifest.amendment;
    if (
      a.version !== 1 ||
      !/^[a-f0-9]{64}$/.test(a.parentSnapshot) ||
      !/^[a-f0-9]{64}$/.test(a.sourceSnapshot) ||
      typeof a.builder !== "string" ||
      !a.builder ||
      !Array.isArray(a.addedFamilies) ||
      !a.addedFamilies.length ||
      a.addedFamilies.some((f) => typeof f !== "string" || !f) ||
      !Number.isInteger(a.routingPaddingCells) ||
      a.routingPaddingCells < 0 ||
      a.routingPaddingCells > 4
    )
      throw new Error("Invalid amendment provenance");
  }
  if (manifest.selection) {
    const s = manifest.selection;
    if (
      !Array.isArray(s.polygon) ||
      s.polygon.length < 3 ||
      s.polygon.length > 128 ||
      !s.polygon.every(
        (p) =>
          Array.isArray(p) &&
          p.length === 2 &&
          p.every(Number.isFinite) &&
          Math.abs(p[0]) <= 180 &&
          Math.abs(p[1]) <= 85,
      ) ||
      typeof s.parentSnapshot !== "string" ||
      !/^[a-f0-9]{64}$/.test(s.parentSnapshot) ||
      typeof s.boundaryPolicy !== "string"
    )
      throw new Error("Invalid selection metadata");
  }
  if (
    manifest.featureKinds &&
    (!Array.isArray(manifest.featureKinds) ||
      new Set(manifest.featureKinds).size !== manifest.featureKinds.length ||
      manifest.featureKinds.some(
        (k) =>
          ![
            "buildings",
            "water",
            "railways",
            "roads",
            "land",
            "boundaries",
            "objects",
          ].includes(k),
      ))
  )
    throw new Error("Invalid feature category metadata");
  if (
    manifest.selection?.routingPaddingCells !== undefined &&
    (!Number.isInteger(manifest.selection.routingPaddingCells) ||
      manifest.selection.routingPaddingCells < 0 ||
      manifest.selection.routingPaddingCells > 4)
  )
    throw new Error("Invalid routing selection padding");
  validateTransportMetadata(manifest.transport, manifest.capabilities);
  if (manifest.routing) {
    const r = manifest.routing;
    if (
      r.cells &&
      (r.cells.zoom !== 14 ||
        r.cells.codec !== "rcl1" ||
        !Number.isSafeInteger(r.cells.count) ||
        r.cells.count < 1)
    )
      throw new Error("Invalid routing cell metadata");
    if (
      r.profile !== "walking-v1" ||
      r.block !== "routing/walking" ||
      r.scope !== "retained-source-extract" ||
      r.snapLimitMeters !== 150 ||
      ![r.nodes, r.segments, r.bytes, r.skippedWays].every(
        (n) => Number.isSafeInteger(n) && n >= 0,
      ) ||
      r.nodes > 8_000_000 ||
      r.segments > 12_000_000 ||
      r.bytes !== 12 + r.nodes * 24 + r.segments * 20 ||
      !blocks.some(
        (b) => b.key === r.block && (b.rawLength ?? b.length) === r.bytes,
      )
    )
      throw new Error("Invalid routing metadata");
  }
  if (manifest.capabilities.includes("walking-routing") && !manifest.routing)
    throw new Error("Missing routing metadata");
  for (const [capability, key] of [
    ["location-search", "search/locations"],
    ["administrative-boundaries", "boundaries/index"],
    ["source-objects", "objects/index"],
    ["reverse-street", "search/streets"],
  ]) {
    if (
      manifest.capabilities.includes(capability!) &&
      !blocks.some((b) => b.key === key)
    )
      throw new Error(`Missing geocoding block: ${key}`);
  }
  validateBlocks(header, manifest, blocks);
  if (header.version === 2) {
    validateBlocks(header, manifest, pages);
    const pageKeys = new Set<string>();
    for (const p of pages) {
      if (
        ![p.z, p.x, p.y, p.count].every(Number.isInteger) ||
        (isTilePrefix(p.prefix ?? "tile")
          ? p.z < manifest.minZoom ||
            p.z > manifest.maxZoom ||
            (p.prefix
              ? !manifest.tileLayers?.includes(p.prefix.slice(5) as MapLayer)
              : !!manifest.tileLayers)
          : p.prefix?.startsWith("raster/")
            ? !manifest.rasters?.some(
                (r) =>
                  p.prefix === `raster/${r.id}` &&
                  p.z >= r.minZoom &&
                  p.z <= r.maxZoom,
              )
            : p.prefix?.startsWith("members/")
              ? p.z !== 26 ||
                !manifest.composition?.members.some(
                  (m) => p.prefix === `members/${m.id}`,
                )
              : isRoutingCell(`${p.prefix}/`)
                ? p.z !== routingZoom(manifest, p.prefix!)
                : p.prefix === "labels/settlements" ||
                    p.prefix === "query/peaks-data"
                  ? p.z !== 8
                  : /^labels\/(roads|pois)\/(13|14|15|16|17)$/.test(p.prefix!)
                    ? p.z !== manifest.labelZoom
                    : /^objects\/(geometry|topology|records|spatial|ids|lookup|tag-values|tag-index|tag-pages)$/.test(
                          p.prefix!,
                        )
                      ? p.z !== 26
                      : /^boundaries\/(records|geometry)$/.test(p.prefix!)
                        ? p.z !== 16
                        : pagedZoom(p.prefix!) !== undefined
                          ? p.z !== pagedZoom(p.prefix!)
                          : !/^features\/(buildings|water|railways|roads|land)$/.test(
                              p.prefix!,
                            ) || p.z !== manifest.featureZoom) ||
        p.x < 0 ||
        p.y < 0 ||
        p.x >= Math.ceil(2 ** p.z / INDEX_PAGE_SIZE) ||
        p.y >= Math.ceil(2 ** p.z / INDEX_PAGE_SIZE) ||
        p.count < 1 ||
        p.count > INDEX_PAGE_SIZE ** 2 ||
        p.rawLength! > MAX_METADATA ||
        p.codec !== "gzip" ||
        p.key !== pageKey(p.prefix ?? "tile", p.z, p.x, p.y) ||
        pageKeys.has(p.key)
      )
        throw new Error("Invalid ATLAS directory page");
      pageKeys.add(p.key);
    }
    if (
      blocks.some(
        (b) =>
          (spatialAddress(b.key) !== null && !/^labels\/\d+\//.test(b.key)) ||
          b.key.startsWith("index/") ||
          b.offset + b.length >
            (pages[0]?.offset ?? header.fileLength - header.payloadOffset),
      )
    )
      throw new Error("Invalid ATLAS root directory");
  }
  const routingCells =
    header.version === 1
      ? blocks.filter((b) => b.key.startsWith("routing/cells/")).length
      : pages
          .filter((p) => p.prefix === "routing/cells")
          .reduce((n, p) => n + p.count, 0);
  if (
    routingCells !== (manifest.routing?.cells?.count ?? 0) ||
    manifest.capabilities.includes("paged-walking-routing") !==
      !!manifest.routing?.cells
  )
    throw new Error("Routing cell directory does not match metadata");
  for (const mode of TRANSPORT_MODES) {
    const prefix = `routing/${mode}/cells`;
    const count =
      header.version === 1
        ? blocks.filter((b) => b.key.startsWith(`${prefix}/`)).length
        : pages
            .filter((p) => p.prefix === prefix)
            .reduce((n, p) => n + p.count, 0);
    if (count !== (manifest.transport?.profiles[mode]?.count ?? 0))
      throw new Error("Transport cell directory mismatch");
  }
  const tileCount =
    header.version === 1
      ? blocks.filter((b) => b.key.startsWith("tile/")).length
      : pages
          .filter((p) => isTilePrefix(p.prefix ?? "tile"))
          .reduce((n, p) => n + p.count, 0);
  return {
    header,
    manifest,
    blocks,
    pages,
    tileCount,
    blockCount: blocks.length + pages.reduce((n, p) => n + p.count, 0),
  };
}
export function validateBlocks(
  header: Header,
  manifest: Manifest,
  blocks: Block[],
) {
  if (!Array.isArray(blocks)) throw new Error("Invalid ATLAS block directory");
  const keys = new Set<string>();
  let end = 0;
  for (const block of blocks) {
    if (
      (block.codec !== undefined && block.codec !== "gzip") ||
      (block.codec === "gzip" &&
        (!Number.isSafeInteger(block.rawLength) ||
          block.rawLength! < 0 ||
          block.rawLength! > 768 * 1024 * 1024)) ||
      (block.codec === undefined && block.rawLength !== undefined) ||
      typeof block.key !== "string" ||
      keys.has(block.key) ||
      !Number.isSafeInteger(block.offset) ||
      !Number.isSafeInteger(block.length) ||
      block.offset < end ||
      block.length < 0 ||
      block.offset + block.length > header.fileLength - header.payloadOffset ||
      !/^[a-f0-9]{64}$/.test(block.hash)
    )
      throw new Error("Invalid ATLAS block directory");
    if (
      block.key.startsWith("labels/") &&
      block.key !== "labels/places" &&
      !block.key.startsWith("labels/settlements/")
    ) {
      const match =
        /^labels\/(\d+)\/(\d+)\/(\d+)(?:\/(roads|pois)\/(13|14|15|16|17))?$/.exec(
          block.key,
        );
      if (
        !match ||
        Number(match[1]) !== manifest.labelZoom ||
        Number(match[2]) >= 2 ** manifest.labelZoom! ||
        Number(match[3]) >= 2 ** manifest.labelZoom!
      )
        throw new Error("Invalid label address");
    }
    if (
      block.key.startsWith("labels/settlements/") ||
      block.key.startsWith("query/peaks-data/")
    ) {
      const a = spatialAddress(block.key);
      if (
        !a ||
        a.z !== 8 ||
        a.x >= 256 ||
        a.y >= 256 ||
        (block.rawLength ?? block.length) > 4 * 1024 * 1024
      )
        throw new Error("Invalid geographic semantic page");
    }
    if (
      block.key.startsWith("boundaries/") &&
      block.key !== "boundaries/index"
    ) {
      const a = spatialAddress(block.key);
      if (
        !a ||
        a.z !== 16 ||
        a.x >= 65536 ||
        a.y >= 65536 ||
        block.key !== `${a.prefix}/16/${a.x}/${a.y}` ||
        (a.prefix === "boundaries/records" &&
          (block.rawLength ?? block.length) > 1024 ** 2)
      )
        throw new Error("Invalid boundary block address or size");
    }
    if (block.key.startsWith("members/")) {
      const a = spatialAddress(block.key),
        member = manifest.composition?.members.find(
          (m) => a?.prefix === `members/${m.id}`,
        );
      if (
        !a ||
        !member ||
        a.z !== 26 ||
        a.y !== 0 ||
        a.x < 0 ||
        a.x >= Math.ceil(member.bytes / MEMBER_CHUNK_BYTES) ||
        block.codec ||
        block.length !==
          Math.min(MEMBER_CHUNK_BYTES, member.bytes - a.x * MEMBER_CHUNK_BYTES)
      )
        throw new Error("Invalid embedded member block");
    }
    if (block.key.startsWith("objects/") && block.key !== "objects/index") {
      const a = spatialAddress(block.key);
      if (
        !a ||
        a.z !== 26 ||
        a.x >= 2 ** 26 ||
        a.y >= 2 ** 26 ||
        (block.rawLength ?? block.length) > 4 * 1024 ** 2
      )
        throw new Error("Invalid source-object block address or size");
    }
    if (block.key.startsWith("features/") && block.key !== "features/geojson") {
      const a = spatialAddress(block.key);
      if (
        !a ||
        a.z !== (pagedZoom(a.prefix) ?? manifest.featureZoom) ||
        ((a.prefix === "features/attributes" ||
          a.prefix === "features/geometry") &&
          (manifest.featureSchema !== 2 ||
            (block.rawLength ?? block.length) > 4 * 1024 ** 2)) ||
        a.x < 0 ||
        a.y < 0 ||
        a.x >= 2 ** a.z ||
        a.y >= 2 ** a.z
      )
        throw new Error("Invalid feature address");
    }
    if (
      block.key.startsWith("search/") &&
      !["search/locations", "search/streets"].includes(block.key)
    ) {
      const a = spatialAddress(block.key);
      if (
        !a ||
        a.z !== pagedZoom(a.prefix) ||
        a.x >= 2 ** a.z ||
        a.y >= 2 ** a.z ||
        block.key !== `${a.prefix}/${a.z}/${a.x}/${a.y}` ||
        (block.rawLength ?? block.length) > 4 * 1024 * 1024
      )
        throw new Error("Invalid search page address or size");
    }
    if (isRoutingCell(block.key)) {
      const a = spatialAddress(block.key);
      if (
        !a ||
        a.z !== routingZoom(manifest, a.prefix) ||
        a.x >= 2 ** a.z ||
        a.y >= 2 ** a.z ||
        block.key !== `${a.prefix}/${a.z}/${a.x}/${a.y}` ||
        (block.rawLength ?? block.length) >
          (manifest.transport?.profiles[
            block.key.split("/")[1] as TransportMode
          ]?.codec === "rcl3"
            ? 20
            : 16) *
            1024 *
            1024
      )
        throw new Error("Invalid routing cell address or size");
    }
    if (block.key.startsWith("raster/")) {
      const a = spatialAddress(block.key),
        r = manifest.rasters?.find((r) => a?.prefix === `raster/${r.id}`);
      if (
        !a ||
        !r ||
        a.z < r.minZoom ||
        a.z > r.maxZoom ||
        a.x >= 2 ** a.z ||
        a.y >= 2 ** a.z ||
        block.key !== `${a.prefix}/${a.z}/${a.x}/${a.y}` ||
        (block.rawLength ?? block.length) > 8 * 1024 ** 2
      )
        throw new Error("Invalid raster tile address or size");
    }
    if (block.key.startsWith("tile/")) {
      if (
        ![block.z, block.x, block.y].every(Number.isInteger) ||
        block.z! < manifest.minZoom ||
        block.z! > manifest.maxZoom ||
        block.x! < 0 ||
        block.y! < 0 ||
        block.x! >= 2 ** block.z! ||
        block.y! >= 2 ** block.z! ||
        (manifest.tileLayers
          ? !tileLayer(block.key) ||
            !manifest.tileLayers.includes(tileLayer(block.key)!) ||
            block.key !==
              `tile/${tileLayer(block.key)}/${block.z}/${block.x}/${block.y}`
          : block.key !== `tile/${block.z}/${block.x}/${block.y}`)
      )
        throw new Error("Invalid tile address");
    }
    keys.add(block.key);
    end = block.offset + block.length;
  }
}
export async function sha256(bytes: Uint8Array): Promise<string> {
  const digest = await crypto.subtle.digest(
    "SHA-256",
    bytes as Uint8Array<ArrayBuffer>,
  );
  return Array.from(new Uint8Array(digest), (b) =>
    b.toString(16).padStart(2, "0"),
  ).join("");
}
export function project(lon: number, lat: number): [number, number] {
  const radians =
    (Math.max(-85.05112878, Math.min(85.05112878, lat)) * Math.PI) / 180;
  return [
    (lon + 180) / 360,
    (1 - Math.log(Math.tan(radians) + 1 / Math.cos(radians)) / Math.PI) / 2,
  ];
}
export function unproject(x: number, y: number): [number, number] {
  return [
    x * 360 - 180,
    (Math.atan(Math.sinh(Math.PI * (1 - 2 * y))) * 180) / Math.PI,
  ];
}