{"_id":"@closerclick/closer-click-geo","_rev":"2-c8d30216323149464d3c4f373db55d2e","name":"@closerclick/closer-click-geo","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@closerclick/closer-click-geo","version":"0.1.0","keywords":["geolocation","geospatial","postgis","geohash","closer-click","discovery","p2p"],"author":{"name":"seyacat"},"license":"MIT","_id":"@closerclick/closer-click-geo@0.1.0","maintainers":[{"name":"mycloserclick","email":"admin@closer.click"}],"homepage":"https://github.com/closerclick/closer-click-geo#readme","bugs":{"url":"https://github.com/closerclick/closer-click-geo/issues"},"dist":{"shasum":"1f6e01973630ed453cdaa53c4da85cf1312ba6c3","tarball":"https://registry.npmjs.org/@closerclick/closer-click-geo/-/closer-click-geo-0.1.0.tgz","fileCount":7,"integrity":"sha512-ht1chiIWVHCxQFFVdAi0X/RsYgQTzyezpJe4eZEI2nE7rnh1PP+uJg7CVSEcAvDbAarB5ZzH33YoftsTEcj8Yg==","signatures":[{"sig":"MEQCIHJAzH+gXofhIJkhza5MY+zyQeGZw1aAfi/12Uy8pAR4AiAqIxLhdj+KFVdi7YWNdmi6qV5QWKJqlW1GdL0+IyHm9Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16679},"main":"src/index.js","type":"module","types":"src/index.d.ts","module":"src/index.js","exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js"}},"gitHead":"c847823280934c91ac6483e54a6e4c1e26e84561","scripts":{"test":"node --test"},"_npmUser":{"name":"mycloserclick","email":"admin@closer.click"},"repository":{"url":"git+https://github.com/closerclick/closer-click-geo.git","type":"git"},"_npmVersion":"11.12.1","description":"Cliente del índice geo de Closer Click (geo.closer.click): pins georreferenciados firmados con el vault, consulta por radio (PostGIS)","directories":{},"_nodeVersion":"25.9.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/closer-click-geo_0.1.0_1780369153477_0.31330938390916185","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@closerclick/closer-click-geo","version":"0.2.0","description":"Cliente del índice geo de Closer Click (geo.closer.click): pins georreferenciados firmados con el vault, consulta por radio (PostGIS)","type":"module","main":"src/index.js","module":"src/index.js","types":"src/index.d.ts","exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js"}},"scripts":{"test":"node --test"},"keywords":["geolocation","geospatial","postgis","geohash","closer-click","discovery","p2p"],"author":{"name":"seyacat"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/closerclick/closer-click-geo.git"},"gitHead":"3cf6dc8943e2c700aff5214df7f9279778a644be","_id":"@closerclick/closer-click-geo@0.2.0","bugs":{"url":"https://github.com/closerclick/closer-click-geo/issues"},"homepage":"https://github.com/closerclick/closer-click-geo#readme","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-/I9UGJ9qNUp5PVkr3SKVUcunmtWvC7p4fFH0hS3jMVYrwXEA7gfHIhgOQMatW3jWR2hyQropkDQ6P9z+RLVndw==","shasum":"0bf4a5b5938171f5087c53ec66763055661b7712","tarball":"https://registry.npmjs.org/@closerclick/closer-click-geo/-/closer-click-geo-0.2.0.tgz","fileCount":7,"unpackedSize":18045,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHy/xK5yjmwOW+gW7ZtE4ebPQ8sJE7PegS6sSIkuzsJiAiANWWNqwL2xVVbm5rlpkcJG5B8RimUKGtCqAWSaR69Ltg=="}]},"_npmUser":{"name":"mycloserclick","email":"admin@closer.click"},"directories":{},"maintainers":[{"name":"mycloserclick","email":"admin@closer.click"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/closer-click-geo_0.2.0_1780408769635_0.9387298934674246"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-02T02:59:13.350Z","modified":"2026-06-02T13:59:29.898Z","0.1.0":"2026-06-02T02:59:13.617Z","0.2.0":"2026-06-02T13:59:29.773Z"},"bugs":{"url":"https://github.com/closerclick/closer-click-geo/issues"},"author":{"name":"seyacat"},"license":"MIT","homepage":"https://github.com/closerclick/closer-click-geo#readme","keywords":["geolocation","geospatial","postgis","geohash","closer-click","discovery","p2p"],"repository":{"type":"git","url":"git+https://github.com/closerclick/closer-click-geo.git"},"description":"Cliente del índice geo de Closer Click (geo.closer.click): pins georreferenciados firmados con el vault, consulta por radio (PostGIS)","maintainers":[{"name":"mycloserclick","email":"admin@closer.click"}],"readme":"# @closerclick/closer-click-geo\n\nÍndice de **descubrimiento georreferenciado** del ecosistema CloserClick:\n`geo.closer.click`. Una identidad publica un **pin firmado** (lat/lng + payload)\ncon TTL corto; cualquiera consulta los pins dentro de un **radio** (PostGIS hace\nla query espacial). Pensado para casos tipo \"Uber\", delivery, \"cerca de mí\",\nmarketplace local, eventos.\n\nEs el **cuarto pilar** del ecosistema, complementario a los tres existentes:\n\n| Pilar | Paquete | Rol |\n|-------|---------|-----|\n| Identidad | `closer-click-identity` | clave del vault, firma |\n| Transporte | `closer-click-proxy-client` | mensajería, canales, WebRTC |\n| Almacenamiento | `closer-click-store` | datos del usuario en el navegador |\n| **Descubrimiento geo** | **`closer-click-geo`** | **encontrar identidades cercanas** |\n\n## El pin es un anuncio efímero, no almacenamiento\n\nUna publicación geo **no es persistente**: es un **anuncio** que apunta a otro\nservicio (el messenger) donde ocurre la transacción real. El pin lleva el\n**pubkey** de la identidad, que es el handle con el que se la contacta por el\nproxy. El dato durable de la transacción vive en el messenger, no acá.\n\nPor eso el **techo de vida de un pin es 24 h**, alineado con la ventana de\n**mensajes offline del proxy**: sin que la identidad lo *hidrate* (republicar),\nun anuncio no debe sobrevivir más que un mensaje offline. Apps que necesiten\npresencia \"ahora mismo\" usan TTL cortos (default 10 min); anuncios tipo\nclasificado pueden llegar al cap de 24 h. El server purga los expirados.\n\n## Principio de diseño: descubrir acá, hablar por el proxy\n\nEste índice es **SOLO descubrimiento**. El flujo correcto es:\n\n1. **Publicás** un pin firmado con `publishPin()` (opt-in, TTL corto).\n2. Otra identidad te **encuentra** con `queryRadius()`.\n3. A partir de ahí, **todo el contacto en vivo va por el proxy**\n   (`@closerclick/closer-click-proxy-client`): el \"pedido de viaje\", el handshake\n   y el **streaming de ubicación en tiempo real** se hacen con `sendByPubkey` /\n   canal / WebRTC. **No** hagas streaming de posición a alta frecuencia contra\n   este índice — eso es transporte y ya está resuelto.\n\nCada pin (y cada query) trae el **pubkey JWK** de la identidad: ese es el handle\ncon el que el proxy enruta (`sendByPubkey`). Identidad de descubrimiento e\nidentidad de transporte coinciden, como manda el ecosistema.\n\n## Identidad: el vault es la única fuente\n\nEl cliente **no genera ni guarda claves**. Le inyectás `signData` y\n`getPublicKeyJwk` desde `@closerclick/closer-click-identity` (el vault\n`id.closer.click`). Mismo sobre firmado `{data, signature}` y misma\nserialización canónica que el proxy-client.\n\n## Instalación\n\n```bash\nnpm i @closerclick/closer-click-geo\n```\n\n## Uso (cliente)\n\n```js\nimport { createGeoClient } from '@closerclick/closer-click-geo'\nimport identity from '@closerclick/closer-click-identity' // el vault\n\nconst geo = createGeoClient({\n  signData: identity.signData,\n  getPublicKeyJwk: identity.getPublicKeyJwk,\n  // baseUrl: 'https://geo.closer.click'  // default\n})\n\n// 1) Publicar mi pin (opt-in). Se reemplaza el anterior; no hay historial.\nawait geo.publishPin({\n  lat: -2.1709, lng: -79.9224,\n  payload: { role: 'driver', seats: 4 },\n  tags: ['comida', 'vegano'],  // etiquetas de búsqueda (se normalizan)\n  ttlMs: 10 * 60 * 1000        // 10 min (el server lo capa a 1h)\n})\n\n// 2) Buscar cerca, por radio + tags (overlap: alguna de las etiquetas) y/o filter\nconst { pins } = await geo.queryRadius({\n  lat: -2.1700, lng: -79.9200,\n  radiusMeters: 3000,\n  tags: ['comida', 'bici'],    // pins con ALGUNA de estas etiquetas\n  filter: { role: 'driver' }   // containment JSONB sobre payload (opcional)\n})\n// pins: [{ publickey, lat, lng, geohash, payload, tags, distanceMeters, expiresAt }, ...]\n\n// 3) Contactar al más cercano POR EL PROXY (no por este índice)\n//    proxyClient.sendByPubkey([pins[0].publickey], { type: 'ride-request', ... })\n\n// 4) Retirar mi pin antes de tiempo\nawait geo.removePin()\n```\n\n### Privacidad (no rompe la filosofía CloserClick)\n\nUn índice de ubicación consultable es lo más sensible del ecosistema. Por eso:\n\n- **Un pin por identidad, con overwrite** — no se guarda historial de ubicaciones.\n- **TTL corto** por diseño (default 10 min, cap del server 1 h). Un job purga\n  expirados cada minuto.\n- **Opt-in** siempre: publicar es una acción explícita; `removePin()` lo retira.\n- **Geohash grueso** para descubrimiento (default 7 chars ≈ 76 m; bajalo con\n  `geohashPrecision` para exponer menos). La recomendación es descubrir por\n  bucket y **negociar las coords exactas P2P por el proxy** tras consentimiento.\n- **Sólo metadata de app en `payload`** — nunca datos personales del usuario.\n\n## API del servicio (HTTP/JSON)\n\n| Método | Ruta | Auth | Descripción |\n|--------|------|------|-------------|\n| `PUT` | `/pins` | sobre firmado | publica/reemplaza el pin de la identidad |\n| `DELETE` | `/pins` | sobre firmado | retira el pin (tombstone) |\n| `GET` | `/pins?lat&lng&r&limit&filter` | pública | pins dentro del radio, por distancia |\n| `GET` | `/health` | — | liveness |\n\nEl servidor verifica la firma ECDSA P-256 (JWK del vault) sobre el `data`\ncanónico, chequea frescura (`issuedAt` dentro de ±5 min, anti-replay) y capa el\nTTL. Ver [`server/`](./server) y [`DEPLOY.md`](./DEPLOY.md).\n\n## Estructura\n\n```\nsrc/            cliente npm (@closerclick/closer-click-geo)\n  index.js      createGeoClient: publishPin / queryRadius / removePin\n  geohash.js    encode base32 (compartido)\n  canonical.js  serialización canónica (igual que el resto del ecosistema)\nserver/         servicio geo.closer.click\n  server.js     HTTP/JSON nativo\n  db.js         capa PostGIS (pg)\n  schema.sql    tabla pins (geography + GiST)\n  signature.js  verificación de sobres firmados\n```\n\n## Licencia\n\nMIT\n","readmeFilename":"README.md"}