Files
backend/docs/typescript-frontend-integration.md
Andriy Oblivantsev 184c5cb59f
CI / test (push) Successful in 5s
Describe Key methods in typescript-frontend-integration.md
Add descriptions and group by category: Key storage, Auth, Collections, Features

Made-with: Cursor
2026-03-01 14:29:49 +00:00

7.9 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.

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

  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.