// node_modules/@noble/ed25519/index.js /*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ var ed25519_CURVE = { p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn, n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn, h: 8n, a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn, d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n, Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an, Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n }; var { p: P, n: N, Gx, Gy, a: _a, d: _d, h } = ed25519_CURVE; var L = 32; var L2 = 64; var captureTrace = (...args) => { if ("captureStackTrace" in Error && typeof Error.captureStackTrace === "function") { Error.captureStackTrace(...args); } }; var err = (message = "") => { const e = new Error(message); captureTrace(e, err); throw e; }; var isBig = (n) => typeof n === "bigint"; var isStr = (s) => typeof s === "string"; var isBytes = (a) => a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array"; var abytes = (value, length, title = "") => { const bytes = isBytes(value); const len = value?.length; const needsLen = length !== undefined; if (!bytes || needsLen && len !== length) { const prefix = title && `"${title}" `; const ofLen = needsLen ? ` of length ${length}` : ""; const got = bytes ? `length=${len}` : `type=${typeof value}`; err(prefix + "expected Uint8Array" + ofLen + ", got " + got); } return value; }; var u8n = (len) => new Uint8Array(len); var u8fr = (buf) => Uint8Array.from(buf); var padh = (n, pad) => n.toString(16).padStart(pad, "0"); var bytesToHex = (b) => Array.from(abytes(b)).map((e) => padh(e, 2)).join(""); var C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; var _ch = (ch) => { if (ch >= C._0 && ch <= C._9) return ch - C._0; if (ch >= C.A && ch <= C.F) return ch - (C.A - 10); if (ch >= C.a && ch <= C.f) return ch - (C.a - 10); return; }; var hexToBytes = (hex) => { const e = "hex invalid"; if (!isStr(hex)) return err(e); const hl = hex.length; const al = hl / 2; if (hl % 2) return err(e); const array = u8n(al); for (let ai = 0, hi = 0;ai < al; ai++, hi += 2) { const n1 = _ch(hex.charCodeAt(hi)); const n2 = _ch(hex.charCodeAt(hi + 1)); if (n1 === undefined || n2 === undefined) return err(e); array[ai] = n1 * 16 + n2; } return array; }; var cr = () => globalThis?.crypto; var subtle = () => cr()?.subtle ?? err("crypto.subtle must be defined, consider polyfill"); var concatBytes = (...arrs) => { const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0)); let pad = 0; arrs.forEach((a) => { r.set(a, pad); pad += a.length; }); return r; }; var big = BigInt; var assertRange = (n, min, max, msg = "bad number: out of range") => isBig(n) && min <= n && n < max ? n : err(msg); var M = (a, b = P) => { const r = a % b; return r >= 0n ? r : b + r; }; var modN = (a) => M(a, N); var invert = (num, md) => { if (num === 0n || md <= 0n) err("no inverse n=" + num + " mod=" + md); let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n; while (a !== 0n) { const q = b / a, r = b % a; const m = x - u * q, n = y - v * q; b = a, a = r, x = u, y = v, u = m, v = n; } return b === 1n ? M(x, md) : err("no inverse"); }; var apoint = (p) => p instanceof Point ? p : err("Point expected"); var B256 = 2n ** 256n; class Point { static BASE; static ZERO; X; Y; Z; T; constructor(X, Y, Z, T) { const max = B256; this.X = assertRange(X, 0n, max); this.Y = assertRange(Y, 0n, max); this.Z = assertRange(Z, 1n, max); this.T = assertRange(T, 0n, max); Object.freeze(this); } static CURVE() { return ed25519_CURVE; } static fromAffine(p) { return new Point(p.x, p.y, 1n, M(p.x * p.y)); } static fromBytes(hex, zip215 = false) { const d = _d; const normed = u8fr(abytes(hex, L)); const lastByte = hex[31]; normed[31] = lastByte & ~128; const y = bytesToNumLE(normed); const max = zip215 ? B256 : P; assertRange(y, 0n, max); const y2 = M(y * y); const u = M(y2 - 1n); const v = M(d * y2 + 1n); let { isValid, value: x } = uvRatio(u, v); if (!isValid) err("bad point: y not sqrt"); const isXOdd = (x & 1n) === 1n; const isLastByteOdd = (lastByte & 128) !== 0; if (!zip215 && x === 0n && isLastByteOdd) err("bad point: x==0, isLastByteOdd"); if (isLastByteOdd !== isXOdd) x = M(-x); return new Point(x, y, 1n, M(x * y)); } static fromHex(hex, zip215) { return Point.fromBytes(hexToBytes(hex), zip215); } get x() { return this.toAffine().x; } get y() { return this.toAffine().y; } assertValidity() { const a = _a; const d = _d; const p = this; if (p.is0()) return err("bad point: ZERO"); const { X, Y, Z, T } = p; const X2 = M(X * X); const Y2 = M(Y * Y); const Z2 = M(Z * Z); const Z4 = M(Z2 * Z2); const aX2 = M(X2 * a); const left = M(Z2 * M(aX2 + Y2)); const right = M(Z4 + M(d * M(X2 * Y2))); if (left !== right) return err("bad point: equation left != right (1)"); const XY = M(X * Y); const ZT = M(Z * T); if (XY !== ZT) return err("bad point: equation left != right (2)"); return this; } equals(other) { const { X: X1, Y: Y1, Z: Z1 } = this; const { X: X2, Y: Y2, Z: Z2 } = apoint(other); const X1Z2 = M(X1 * Z2); const X2Z1 = M(X2 * Z1); const Y1Z2 = M(Y1 * Z2); const Y2Z1 = M(Y2 * Z1); return X1Z2 === X2Z1 && Y1Z2 === Y2Z1; } is0() { return this.equals(I); } negate() { return new Point(M(-this.X), this.Y, this.Z, M(-this.T)); } double() { const { X: X1, Y: Y1, Z: Z1 } = this; const a = _a; const A = M(X1 * X1); const B = M(Y1 * Y1); const C2 = M(2n * M(Z1 * Z1)); const D = M(a * A); const x1y1 = X1 + Y1; const E = M(M(x1y1 * x1y1) - A - B); const G = D + B; const F = G - C2; const H = D - B; const X3 = M(E * F); const Y3 = M(G * H); const T3 = M(E * H); const Z3 = M(F * G); return new Point(X3, Y3, Z3, T3); } add(other) { const { X: X1, Y: Y1, Z: Z1, T: T1 } = this; const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); const a = _a; const d = _d; const A = M(X1 * X2); const B = M(Y1 * Y2); const C2 = M(T1 * d * T2); const D = M(Z1 * Z2); const E = M((X1 + Y1) * (X2 + Y2) - A - B); const F = M(D - C2); const G = M(D + C2); const H = M(B - a * A); const X3 = M(E * F); const Y3 = M(G * H); const T3 = M(E * H); const Z3 = M(F * G); return new Point(X3, Y3, Z3, T3); } subtract(other) { return this.add(apoint(other).negate()); } multiply(n, safe = true) { if (!safe && (n === 0n || this.is0())) return I; assertRange(n, 1n, N); if (n === 1n) return this; if (this.equals(G)) return wNAF(n).p; let p = I; let f = G; for (let d = this;n > 0n; d = d.double(), n >>= 1n) { if (n & 1n) p = p.add(d); else if (safe) f = f.add(d); } return p; } multiplyUnsafe(scalar) { return this.multiply(scalar, false); } toAffine() { const { X, Y, Z } = this; if (this.equals(I)) return { x: 0n, y: 1n }; const iz = invert(Z, P); if (M(Z * iz) !== 1n) err("invalid inverse"); const x = M(X * iz); const y = M(Y * iz); return { x, y }; } toBytes() { const { x, y } = this.assertValidity().toAffine(); const b = numTo32bLE(y); b[31] |= x & 1n ? 128 : 0; return b; } toHex() { return bytesToHex(this.toBytes()); } clearCofactor() { return this.multiply(big(h), false); } isSmallOrder() { return this.clearCofactor().is0(); } isTorsionFree() { let p = this.multiply(N / 2n, false).double(); if (N % 2n) p = p.add(this); return p.is0(); } } var G = new Point(Gx, Gy, 1n, M(Gx * Gy)); var I = new Point(0n, 1n, 1n, 0n); Point.BASE = G; Point.ZERO = I; var numTo32bLE = (num) => hexToBytes(padh(assertRange(num, 0n, B256), L2)).reverse(); var bytesToNumLE = (b) => big("0x" + bytesToHex(u8fr(abytes(b)).reverse())); var pow2 = (x, power) => { let r = x; while (power-- > 0n) { r *= r; r %= P; } return r; }; var pow_2_252_3 = (x) => { const x2 = x * x % P; const b2 = x2 * x % P; const b4 = pow2(b2, 2n) * b2 % P; const b5 = pow2(b4, 1n) * x % P; const b10 = pow2(b5, 5n) * b5 % P; const b20 = pow2(b10, 10n) * b10 % P; const b40 = pow2(b20, 20n) * b20 % P; const b80 = pow2(b40, 40n) * b40 % P; const b160 = pow2(b80, 80n) * b80 % P; const b240 = pow2(b160, 80n) * b80 % P; const b250 = pow2(b240, 10n) * b10 % P; const pow_p_5_8 = pow2(b250, 2n) * x % P; return { pow_p_5_8, b2 }; }; var RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; var uvRatio = (u, v) => { const v3 = M(v * v * v); const v7 = M(v3 * v3 * v); const pow = pow_2_252_3(u * v7).pow_p_5_8; let x = M(u * v3 * pow); const vx2 = M(v * x * x); const root1 = x; const root2 = M(x * RM1); const useRoot1 = vx2 === u; const useRoot2 = vx2 === M(-u); const noRoot = vx2 === M(-u * RM1); if (useRoot1) x = root1; if (useRoot2 || noRoot) x = root2; if ((M(x) & 1n) === 1n) x = M(-x); return { isValid: useRoot1 || useRoot2, value: x }; }; var modL_LE = (hash) => modN(bytesToNumLE(hash)); var sha512a = (...m) => hashes.sha512Async(concatBytes(...m)); var hash2extK = (hashed) => { const head = hashed.slice(0, L); head[0] &= 248; head[31] &= 127; head[31] |= 64; const prefix = hashed.slice(L, L2); const scalar = modL_LE(head); const point = G.multiply(scalar); const pointBytes = point.toBytes(); return { head, prefix, scalar, point, pointBytes }; }; var getExtendedPublicKeyAsync = (secretKey) => sha512a(abytes(secretKey, L)).then(hash2extK); var getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes); var hashFinishA = (res) => sha512a(res.hashable).then(res.finish); var _sign = (e, rBytes, msg) => { const { pointBytes: P2, scalar: s } = e; const r = modL_LE(rBytes); const R = G.multiply(r).toBytes(); const hashable = concatBytes(R, P2, msg); const finish = (hashed) => { const S = modN(r + modL_LE(hashed) * s); return abytes(concatBytes(R, numTo32bLE(S)), L2); }; return { hashable, finish }; }; var signAsync = async (message, secretKey) => { const m = abytes(message); const e = await getExtendedPublicKeyAsync(secretKey); const rBytes = await sha512a(e.prefix, m); return hashFinishA(_sign(e, rBytes, m)); }; var hashes = { sha512Async: async (message) => { const s = subtle(); const m = concatBytes(message); return u8n(await s.digest("SHA-512", m.buffer)); }, sha512: undefined }; var W = 8; var scalarBits = 256; var pwindows = Math.ceil(scalarBits / W) + 1; var pwindowSize = 2 ** (W - 1); var precompute = () => { const points = []; let p = G; let b = p; for (let w = 0;w < pwindows; w++) { b = p; points.push(b); for (let i = 1;i < pwindowSize; i++) { b = b.add(p); points.push(b); } p = b.double(); } return points; }; var Gpows = undefined; var ctneg = (cnd, p) => { const n = p.negate(); return cnd ? n : p; }; var wNAF = (n) => { const comp = Gpows || (Gpows = precompute()); let p = I; let f = G; const pow_2_w = 2 ** W; const maxNum = pow_2_w; const mask = big(pow_2_w - 1); const shiftBy = big(W); for (let w = 0;w < pwindows; w++) { let wbits = Number(n & mask); n >>= shiftBy; if (wbits > pwindowSize) { wbits -= maxNum; n += 1n; } const off = w * pwindowSize; const offF = off; const offP = off + Math.abs(wbits) - 1; const isEven = w % 2 !== 0; const isNeg = wbits < 0; if (wbits === 0) { f = f.add(ctneg(isEven, comp[offF])); } else { p = p.add(ctneg(isNeg, comp[offP])); } } if (n !== 0n) err("invalid wnaf"); return { p, f }; }; // src/encoding.ts function bytesToBase64Url(bytes) { const bin = Array.from(bytes).map((b) => String.fromCharCode(b)).join(""); if (typeof btoa !== "undefined") { return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, ""); } const b64 = globalThis.Buffer.from(bytes).toString("base64"); return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, ""); } function base64UrlToBytes(input) { const normalized = input.replace(/-/g, "+").replace(/_/g, "/"); const padLen = (4 - normalized.length % 4) % 4; const b64 = normalized + "=".repeat(padLen); if (typeof atob !== "undefined") { const bin = atob(b64); const out = new Uint8Array(bin.length); for (let i = 0;i < bin.length; i++) { out[i] = bin.charCodeAt(i); } return out; } return new Uint8Array(globalThis.Buffer.from(b64, "base64")); } function textToBytes(value) { return new TextEncoder().encode(value); } // src/keys.ts function randomPrivateKey() { const out = new Uint8Array(32); crypto.getRandomValues(out); return out; } async function generateKeyPair() { const privateKey = randomPrivateKey(); const publicKey = await getPublicKeyAsync(privateKey); return { publicKey: bytesToBase64Url(publicKey), privateKey: bytesToBase64Url(privateKey) }; } async function getPublicKeyFromPrivate(privateKeyBase64) { const privateKey = base64UrlToBytes(privateKeyBase64); const publicKey = await getPublicKeyAsync(privateKey); return bytesToBase64Url(publicKey); } async function signMessage(privateKeyBase64, message) { const privateKey = base64UrlToBytes(privateKeyBase64); const signature = await signAsync(textToBytes(message), privateKey); return bytesToBase64Url(signature); } // src/storage.ts var DEFAULT_KEYS_STORAGE_KEY = "geo_api_keys_v1"; function saveKeys(storage, keys, storageKey = DEFAULT_KEYS_STORAGE_KEY) { storage.setItem(storageKey, JSON.stringify(keys)); } function loadKeys(storage, storageKey = DEFAULT_KEYS_STORAGE_KEY) { const raw = storage.getItem(storageKey); if (!raw) { return null; } const parsed = JSON.parse(raw); if (!parsed.publicKey || !parsed.privateKey) { return null; } return parsed; } function clearKeys(storage, storageKey = DEFAULT_KEYS_STORAGE_KEY) { storage.removeItem(storageKey); } // src/GeoApiClient.ts class GeoApiClient { baseUrl; storage; storageKey; accessToken = null; constructor(baseUrl, storage, storageKey = DEFAULT_KEYS_STORAGE_KEY) { this.baseUrl = baseUrl.replace(/\/+$/g, ""); this.storage = storage; this.storageKey = storageKey; } async ensureKeysInStorage() { const existing = loadKeys(this.storage, this.storageKey); if (existing) { return existing; } const generated = await generateKeyPair(); saveKeys(this.storage, generated, this.storageKey); return generated; } getStoredKeys() { return loadKeys(this.storage, this.storageKey); } async derivePublicKey(privateKey) { return getPublicKeyFromPrivate(privateKey); } importKeys(keys) { saveKeys(this.storage, keys, this.storageKey); } exportKeys() { return loadKeys(this.storage, this.storageKey); } setAccessToken(token) { this.accessToken = token; } async request(path, init = {}) { const headers = new Headers(init.headers ?? {}); headers.set("Content-Type", "application/json"); if (this.accessToken) { headers.set("Authorization", `Bearer ${this.accessToken}`); } const body = init.body === undefined ? undefined : JSON.stringify(init.body); const res = await fetch(`${this.baseUrl}${path}`, { ...init, headers, body }); if (!res.ok) { const maybeJson = await res.json().catch(() => ({})); let msg = maybeJson.error ?? `HTTP ${res.status}`; if (maybeJson.hint) msg += `. ${maybeJson.hint}`; throw new Error(msg); } if (res.status === 204) { return; } return await res.json(); } async getServicePublicKey() { return this.request("/v1/service-key", { method: "GET" }); } async createChallenge(publicKey) { return this.request("/v1/auth/challenge", { method: "POST", body: { publicKey } }); } async registerBySigningServiceKey(publicKey, privateKey) { const { publicKey: servicePublicKey } = await this.getServicePublicKey(); const signature = await signMessage(privateKey, servicePublicKey); await this.request("/v1/auth/register-by-signature", { method: "POST", body: { publicKey, signature } }); } async loginWithSignature(publicKey, privateKey) { const challenge = await this.createChallenge(publicKey); const signature = await signMessage(privateKey, challenge.messageToSign); const response = await this.request("/v1/auth/login", { method: "POST", body: { publicKey, nonce: challenge.nonce, signature } }); this.accessToken = response.accessToken; return response.accessToken; } async createInvitation(payload, inviterPrivateKey) { const payloadStr = JSON.stringify(payload); const payloadB64 = bytesToBase64Url(textToBytes(payloadStr)); const inviteSignature = await signMessage(inviterPrivateKey, `invite:${payloadB64}`); await this.request("/v1/invitations", { method: "POST", body: { invitePayloadB64: payloadB64, inviteSignature } }); } async registerWithInvitation(input) { const proofSignature = await signMessage(input.privateKey, `register:${input.publicKey}:${input.jti}`); await this.request("/v1/auth/register", { method: "POST", body: { publicKey: input.publicKey, invitePayloadB64: input.invitePayloadB64, inviteSignature: input.inviteSignature, proofSignature } }); } async listCollections() { return this.request("/v1/collections", { method: "GET" }); } async createCollection(name) { return this.request("/v1/collections", { method: "POST", body: { name } }); } async updateCollection(collectionId, name) { return this.request(`/v1/collections/${collectionId}`, { method: "PATCH", body: { name } }); } async deleteCollection(collectionId) { return this.request(`/v1/collections/${collectionId}`, { method: "DELETE" }); } async listFeatures(collectionId) { return this.request(`/v1/collections/${collectionId}/features`, { method: "GET" }); } async createPointFeature(collectionId, lon, lat, properties) { return this.request(`/v1/collections/${collectionId}/features`, { method: "POST", body: { geometry: { type: "Point", coordinates: [lon, lat] }, properties } }); } async deleteFeature(featureId) { return this.request(`/v1/features/${featureId}`, { method: "DELETE" }); } async createOrLinkAsset(input) { return this.request("/v1/assets", { method: "POST", body: input }); } async getAssetSignedUploadUrl(assetId, contentType) { return this.request(`/v1/assets/${assetId}/signed-upload`, { method: "POST", body: { contentType: contentType ?? "application/octet-stream" } }); } async setAssetVisibility(assetId, isPublic) { return this.request(`/v1/assets/${assetId}`, { method: "PATCH", body: { isPublic } }); } resolveRelativeLink(path) { if (!path.startsWith("/")) return `${this.baseUrl}/${path}`; return `${this.baseUrl}${path}`; } } export { signMessage, saveKeys, loadKeys, getPublicKeyFromPrivate, generateKeyPair, clearKeys, GeoApiClient, DEFAULT_KEYS_STORAGE_KEY };