Improve TypeScript integration doc with concrete 3D upload flow.
CI / test (push) Successful in 3s

This updates the example to compute SHA-256 from a selected GLB/GLTF file, create/link asset metadata, upload with signed URL, and use share links plus visibility toggling.

Made-with: Cursor
This commit is contained in:
2026-03-02 21:32:21 +00:00
parent efe5907adc
commit 96b5e8f40f
+36 -11
View File
@@ -114,7 +114,7 @@ When `SERVICE_PUBLIC_KEY` (or `ADMIN_PUBLIC_KEY`) is set, users can register wit
Server keys are generated with `./bin/gen-server-keys.sh` and stored in `etc/`.
## Example (TypeScript app)
## Example: place and upload a 3D object (`.glb`)
```ts
import { GeoApiClient } from "../libs/geo-api-client/dist/index.js";
@@ -140,28 +140,53 @@ await client.loginWithSignature(keys.publicKey, keys.privateKey);
const created = await client.createCollection("My Places");
const feature = await client.createPointFeature(created.id, -16.6291, 28.4636, { name: "Santa Cruz" });
// 3D/image asset flow
// Assume this comes from: <input id="modelFile" type="file" accept=".glb,.gltf" />
const fileInput = document.getElementById("modelFile") as HTMLInputElement;
const file = fileInput.files?.[0];
if (!file) throw new Error("Select a .glb/.gltf file first");
const toSha256Hex = async (f: File): Promise<string> => {
const buffer = await f.arrayBuffer();
const digest = await crypto.subtle.digest("SHA-256", buffer);
return Array.from(new Uint8Array(digest))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
};
const checksum = await toSha256Hex(file);
const ext = file.name.toLowerCase().endsWith(".gltf") ? "gltf" : "glb";
// Create metadata (or reuse existing by checksum+ext) and link to feature
const asset = await client.createOrLinkAsset({
featureId: feature.id,
checksum: "sha256hex...",
ext: "glb",
checksum,
ext,
kind: "3d",
mimeType: "model/gltf-binary",
sizeBytes: 1024,
name: "Palm Tree",
description: "Low-poly model",
mimeType: file.type || (ext === "gltf" ? "model/gltf+json" : "model/gltf-binary"),
sizeBytes: file.size,
name: "Palm Tree Model",
description: "3D object placed on map",
isPublic: true,
});
const signed = await client.getAssetSignedUploadUrl(asset.asset.id, "model/gltf-binary");
// fetch(signed.url, { method: signed.method, body: file })
// Upload binary to object storage through signed URL
const signed = await client.getAssetSignedUploadUrl(asset.asset.id, asset.asset.mimeType);
await fetch(signed.url, {
method: signed.method,
headers: asset.asset.mimeType ? { "Content-Type": asset.asset.mimeType } : undefined,
body: file,
});
// Read shareable relative link from feature payload
const features = await client.listFeatures(created.id);
const firstAsset = features.features[0]?.properties?.assets?.[0];
if (firstAsset) {
const shareUrl = client.resolveRelativeLink(firstAsset.link);
console.log("Share URL:", shareUrl);
}
console.log(features);
// Optional: owner can disable public access later
await client.setAssetVisibility(asset.asset.id, false);
```
## Security notes