Files
backend/docs/typescript-frontend-integration.md
Andriy Oblivantsev 1292f204a4
CI / test (pull_request) Successful in 3s
Extend TypeScript client and add Leaflet asset demo.
This adds typed asset APIs to the geo client, covers the 3D/image upload-share flow in integration tests, and introduces a simple Leaflet web demo that places objects on map features and manages sharing visibility via backend links.

Made-with: Cursor
2026-03-02 21:21:52 +00:00

8.5 KiB

TypeScript Frontend Integration Guide

This document explains how frontend developers should integrate with the backend through the reusable TypeScript client at libs/geo-api-client.

See also: Frontend Development — demo app (web/), local dev, build steps.

Asset docs: Assets Storage and Sharing and Docker MinIO Local Development.

Primary backend URL for integration:

  • https://momswap.produktor.duckdns.org/

Deployment: API is proxied via reverse proxy from https://momswap.produktor.duckdns.org to backend at 172.17.0.1:8122. Docker Compose maps port 8122 for the reverse proxy.

Goals

  • Keep cryptographic signing logic in one place.
  • Avoid duplicating API request code in frontend apps.
  • Use a consistent local key storage format across projects.

Client package location

  • Source: libs/geo-api-client/src
  • Entry point: libs/geo-api-client/src/index.ts
  • Build output (browser ESM): libs/geo-api-client/dist/index.js

Build and test the client

cd libs/geo-api-client
bun install
bun test          # unit + integration tests (docs flow)
bun run build

Integration tests in test/integration.test.ts cover the recommended flow: register, login, create collection, create point feature, list features.

Public API (current)

Class: GeoApiClient

Source: GeoApiClient.ts

Constructor:

Key methods:

Key storage

Auth

Collections

Features

Asset API integration note

Asset endpoints are currently available at backend API level (/v1/assets...) and can be called from frontend apps directly with authenticated fetch requests.

Current frontend contract points:

  • Feature list responses include linked media under feature.properties.assets.
  • Each asset includes a backend-relative download path (link) like /v1/assets/{id}/download.
  • Frontend should use this relative path and avoid constructing direct S3 URLs.
  1. Create one GeoApiClient instance per backend base URL.
  2. Call ensureKeysInStorage() when app initializes.
  3. If not yet registered: call registerBySigningServiceKey(publicKey, privateKey) (signs the API service key and publishes your public key).
  4. Use loginWithSignature() to obtain and set a bearer token.
  5. Call collection/feature methods after authentication.
  6. Use importKeys/exportKeys in profile settings UX.

Registration by signing service key

When SERVICE_PUBLIC_KEY (or ADMIN_PUBLIC_KEY) is set, users can register without an invitation:

  1. GET /v1/service-key — fetch the server public key (clients use this for registration and further signed communication).
  2. Sign that key with your private key.
  3. POST /v1/auth/register-by-signature with { publicKey, signature }.

Server keys are generated with ./bin/gen-server-keys.sh and stored in etc/.

Example (TypeScript app)

import { GeoApiClient } from "../libs/geo-api-client/dist/index.js";

const storage = window.localStorage;
const storageLike = {
  getItem: (key: string) => storage.getItem(key),
  setItem: (key: string, value: string) => storage.setItem(key, value),
  removeItem: (key: string) => storage.removeItem(key),
};

const client = new GeoApiClient("https://momswap.produktor.duckdns.org", storageLike);
const keys = await client.ensureKeysInStorage();

// Register (ignored if already registered); then login
try {
  await client.registerBySigningServiceKey(keys.publicKey, keys.privateKey);
} catch (_) {
  // Already registered or registration disabled
}
await client.loginWithSignature(keys.publicKey, keys.privateKey);

const created = await client.createCollection("My Places");
await client.createPointFeature(created.id, -16.6291, 28.4636, { name: "Santa Cruz" });
const features = await client.listFeatures(created.id);
console.log(features);

Security notes

  • Private keys are currently stored in browser storage via the selected storage adapter.
  • If your frontend has stronger security requirements, wrap the storage adapter with your own encryption/decryption layer before calling setItem/getItem.
  • Never send private keys to the backend.

No-build frontend compatibility

For no-bundler apps, import the built ESM file:

<script type="module">
  import { GeoApiClient } from "../libs/geo-api-client/dist/index.js";
  // use client...
</script>

The backend itself serves static UI at /web/, but this library can be consumed by any frontend runtime that supports fetch, TextEncoder, and ES modules.

For local development you can switch the client base URL to http://localhost:8122.