{"_id":"@closerclick/closer-click-notifications","_rev":"3-b341192a17da0acb69c3d1671e3aab3d","name":"@closerclick/closer-click-notifications","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@closerclick/closer-click-notifications","version":"0.1.0","keywords":["closer-click","web-component","custom-element","notifications","web-push","pwa","cross-app"],"author":{"name":"seyacat"},"license":"MIT","_id":"@closerclick/closer-click-notifications@0.1.0","maintainers":[{"name":"mycloserclick","email":"admin@closer.click"}],"homepage":"https://github.com/closerclick/closer-click-notifications#readme","bugs":{"url":"https://github.com/closerclick/closer-click-notifications/issues"},"dist":{"shasum":"917b8c4357b06f43e9b20f1c421f1395bb9fe470","tarball":"https://registry.npmjs.org/@closerclick/closer-click-notifications/-/closer-click-notifications-0.1.0.tgz","fileCount":5,"integrity":"sha512-LU7s465uGnCeBrm5tiwdfIwuTPIgCUPImt0PkbMn8U0R9Fch1fpu9KGnA9nRBYhz7c+ycc65heq6ieGn4LZ5gQ==","signatures":[{"sig":"MEUCIDFoI4JLeqhv/hal93vJbtEXVnVNkO70hiDLgik5LZhcAiEAlKLO4+UBRbbGWRn0Mht9q9/6VVN445VC2lKbq+eAwDc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30761},"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":"a26063a4b77b94141e46c99aba7a2dd5c760bddd","scripts":{"test":"node test/smoke.mjs"},"_npmUser":{"name":"mycloserclick","email":"admin@closer.click"},"repository":{"url":"git+https://github.com/closerclick/closer-click-notifications.git","type":"git"},"_npmVersion":"11.12.1","description":"Notificaciones compartidas del ecosistema Closer Click: controlador data-agnostic (permiso del navegador + preferencias por categoría con scope por app + disparo) y el Web Component <closer-click-notifications> (panel de ajustes). Incluye helper de Web Pu","directories":{},"_nodeVersion":"25.9.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/closer-click-notifications_0.1.0_1780593602007_0.6195811867049656","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@closerclick/closer-click-notifications","version":"0.2.0","keywords":["closer-click","web-component","custom-element","notifications","web-push","pwa","cross-app"],"author":{"name":"seyacat"},"license":"MIT","_id":"@closerclick/closer-click-notifications@0.2.0","maintainers":[{"name":"mycloserclick","email":"admin@closer.click"}],"homepage":"https://github.com/closerclick/closer-click-notifications#readme","bugs":{"url":"https://github.com/closerclick/closer-click-notifications/issues"},"dist":{"shasum":"6190e32c67559a230788bb532a8dfd628278adea","tarball":"https://registry.npmjs.org/@closerclick/closer-click-notifications/-/closer-click-notifications-0.2.0.tgz","fileCount":5,"integrity":"sha512-wJiUUCiw1zKxWs59wUPGaQqjhIf89+MevWV8EF5hmJ0cHP7ec60iHaVa9Osfc/xPU62coMsZrDWp3WTQNR/rUg==","signatures":[{"sig":"MEUCIQDnlCANvq0O3KYlJpgdUtgvYnyiVnnxzvn5JXNYy4ZKGgIgK7lPqTvcx7giIBHWD9KHsscz8iffbih9Rg0+Q4cvBaI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43885},"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":"f6ac559e15b493118fa54daa3f1969121b3809aa","scripts":{"test":"node test/smoke.mjs"},"_npmUser":{"name":"mycloserclick","email":"admin@closer.click"},"repository":{"url":"git+https://github.com/closerclick/closer-click-notifications.git","type":"git"},"_npmVersion":"11.12.1","description":"Notificaciones compartidas del ecosistema Closer Click: controlador data-agnostic (permiso del navegador + preferencias por categoría con scope por app + disparo), el Web Component <closer-click-notifications> (panel de ajustes), helper de Web Push ligado","directories":{},"_nodeVersion":"25.9.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/closer-click-notifications_0.2.0_1780667459665_0.845735921617464","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@closerclick/closer-click-notifications","version":"0.3.0","description":"Notificaciones compartidas del ecosistema Closer Click: controlador data-agnostic (permiso del navegador + preferencias por categoría con scope por app + disparo), el Web Component <closer-click-notifications> (panel de ajustes), helper de Web Push ligado","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/smoke.mjs"},"keywords":["closer-click","web-component","custom-element","notifications","web-push","pwa","cross-app"],"author":{"name":"seyacat"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/closerclick/closer-click-notifications.git"},"gitHead":"f6ac559e15b493118fa54daa3f1969121b3809aa","_id":"@closerclick/closer-click-notifications@0.3.0","bugs":{"url":"https://github.com/closerclick/closer-click-notifications/issues"},"homepage":"https://github.com/closerclick/closer-click-notifications#readme","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-zTdlFkuiQJIIAejtU2qXzMCocJOMCqTOfh5NMNPX4wcCrLz8gn9Xh7UWvu6auDyRm+YXjjRoMzquCQIwTr+FIQ==","shasum":"3ec1c838d4f1772b27d5e4defcf04bb7e6d54087","tarball":"https://registry.npmjs.org/@closerclick/closer-click-notifications/-/closer-click-notifications-0.3.0.tgz","fileCount":5,"unpackedSize":46433,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCH/aKgWvNZroBjPEFkEyjSiLyVNMMW1oIpnqqIz61y8QIgGMn99ijmnz6TcdoWxJBqTMeE2unh6ZnlYehyDK8bCQs="}]},"_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-notifications_0.3.0_1780673352000_0.9464256836621001"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-04T17:20:01.812Z","modified":"2026-06-05T15:29:12.310Z","0.1.0":"2026-06-04T17:20:02.179Z","0.2.0":"2026-06-05T13:50:59.801Z","0.3.0":"2026-06-05T15:29:12.195Z"},"bugs":{"url":"https://github.com/closerclick/closer-click-notifications/issues"},"author":{"name":"seyacat"},"license":"MIT","homepage":"https://github.com/closerclick/closer-click-notifications#readme","keywords":["closer-click","web-component","custom-element","notifications","web-push","pwa","cross-app"],"repository":{"type":"git","url":"git+https://github.com/closerclick/closer-click-notifications.git"},"description":"Notificaciones compartidas del ecosistema Closer Click: controlador data-agnostic (permiso del navegador + preferencias por categoría con scope por app + disparo), el Web Component <closer-click-notifications> (panel de ajustes), helper de Web Push ligado","maintainers":[{"name":"mycloserclick","email":"admin@closer.click"}],"readme":"# @closerclick/closer-click-notifications\n\nNotificaciones compartidas del ecosistema **Closer Click**. Unifica lo que cada\napp reimplementaba por separado (messenger, eco, chess, pronóstico, gymbro):\n\n1. **`createNotifications(config)`** — controlador *data-agnostic* y sin framework:\n   permiso del navegador + **preferencias por categoría con scope por app** +\n   disparo (`notify`) respetando permiso y prefs. Web Push opcional.\n2. **`<closer-click-notifications>`** — Web Component (panel de ajustes): activar\n   permiso, togglear cada categoría, sonido y push. Shadow DOM, bilingüe es/en,\n   temable por CSS vars (`--ccn-*`). **Sin JS de terceros ni cookies.**\n3. **`createVaultPushProvider(...)`** — Web Push (app cerrada) ligado al transporte\n   del ecosistema (`closer-click-proxy-client`) y firmado por el vault de identidad.\n4. **`createShareReceipts(...)`** — **acuses de apertura** de contenido compartido:\n   el autor recibe una notificación (con el mismo enlace) cuando un tercero abre lo\n   que compartió. Mismo transporte (proxy) e identidad (vault); contenido por la\n   cola cifrada, no por el push.\n\nEl ecosistema es mixto Vue/vanilla → la UI va como **custom element** (mismo patrón\nque `closer-click-support` / `closer-click-profile` / `closer-click-nav`).\n\n## Instalar\n\n```bash\nnpm i @closerclick/closer-click-notifications\n```\n\n## Uso (controlador + disparo)\n\n```js\nimport { createNotifications } from '@closerclick/closer-click-notifications'\n\nconst notifications = createNotifications({\n  storageKey: 'eco',                      // scope: namespacea las prefs por app\n  categories: [\n    { key: 'replies', label: { es: 'Respuestas', en: 'Replies' }, hint: { es: 'Cuando responden a tu eco.', en: 'When someone replies.' } },\n    { key: 'reposts', label: { es: 'Reposts', en: 'Reposts' }, default: true },\n  ],\n  sound: true,                            // incluye toggle de sonido (default true)\n})\n\n// Disparar (no hace nada si falta permiso o la categoría está apagada):\nawait notifications.notify('replies', {\n  title: 'Nueva respuesta',\n  body: '@ada respondió tu eco',\n  icon: '/icon-192.png',\n  tag: 'eco-reply',\n  onClick: () => location.assign('/#replies'),\n})\n```\n\n`notify` usa el Service Worker (`registration.showNotification`) cuando hay uno\nactivo (mejor en móvil/PWA) y si no `new Notification`. El **sonido** lo controla\nla preferencia `sound` (vía el flag `silent` del SO).\n\n## Panel de ajustes (Web Component)\n\n```js\nimport '@closerclick/closer-click-notifications'   // registra el custom element\n```\n\n```html\n<closer-click-notifications modal lang=\"es\"></closer-click-notifications>\n```\n\n```js\n// tras montar, asigná el controlador (propiedad JS, no atributo):\ndocument.querySelector('closer-click-notifications').controller = notifications\n```\n\nEn Vue 3, configurá `isCustomElement: (tag) => tag.startsWith('closer-click-')` en\n`compilerOptions` del plugin de Vue, y enlazá el controlador con un `ref`:\n\n```html\n<closer-click-notifications :ref=\"el => el && (el.controller = notifications)\" modal />\n```\n\n### Atributos\n\n| Atributo  | Descripción |\n|-----------|-------------|\n| `modal`   | envuelve en backdrop (click fuera = cerrar, emite `cc-notif-close`) |\n| `heading` | título del panel (override) |\n| `lang`    | `es` \\| `en` \\| `auto` (default `auto`) |\n\n### Propiedad JS\n\n- `.controller` — el objeto devuelto por `createNotifications(...)`.\n\n### Eventos (bubbles, composed)\n\n- `cc-notif-change` — `detail { key, value }` (toggle de categoría/sonido).\n- `cc-notif-permission` — `detail { permission }` (tras pedir permiso).\n- `cc-notif-push` — `detail { enabled }` (toggle de push).\n- `cc-notif-close` — cerrar (X o backdrop en modo `modal`).\n\n## Web Push (app cerrada)\n\n```js\nimport { createNotifications, createVaultPushProvider } from '@closerclick/closer-click-notifications'\nimport { getWebSocketProxyClient } from '@closerclick/closer-click-proxy-client'\nimport { Identity } from '@closerclick/closer-click-identity'\n\nconst notifications = createNotifications({\n  storageKey: 'messenger',\n  categories: [ /* … */ ],\n  push: createVaultPushProvider({\n    proxyClient: () => getWebSocketProxyClient(),\n    identity: () => Identity.connect(),     // instancia o getter (async ok)\n    storageKey: 'messenger',\n  }),\n})\n\n// Re-registra la subscription tras cada identify (los endpoints rotan):\nawait notifications.push.ensureSubscribed()\n```\n\nEl \"timbre\" **no transporta contenido**: el Service Worker despierta y la app\nreconecta e `identify()` drena la cola cifrada del proxy. La subscription se liga\na la **misma pubkey del vault** usada en `identify`, con un sobre firmado por el vault.\n\n## Acuses de apertura (`createShareReceipts`)\n\nAvisa al **autor** cuando un tercero **abre** un contenido que compartió, con el\n**mismo enlace** de vuelta (para re-ver el contenido desde la notificación). Solo\nfunciona si el enlace permite recuperar la **pubkey del autor** (p. ej. el blob\nfirmado del pronosticador): así el que abre puede enrutar el acuse por\n`sendByPubkey` (cola offline 24h del proxy).\n\n```js\nimport { createNotifications, createShareReceipts } from '@closerclick/closer-click-notifications'\nimport { getWebSocketProxyClient } from '@closerclick/closer-click-proxy-client'\nimport { Identity } from '@closerclick/closer-click-identity'\n\nconst notifications = createNotifications({\n  storageKey: 'mundial',\n  categories: [\n    { key: 'shareOpened', label: { es: 'Aperturas de lo que compartí', en: 'Opens of what I shared' } },\n  ],\n})\n\nconst receipts = createShareReceipts({\n  proxyClient: () => getWebSocketProxyClient(),\n  identity: () => Identity.connect(),\n  notifications,                  // dispara notify('shareOpened', …) con data.url\n  // render(env) → { title, body, ... } | null  (opcional: personaliza el contenido)\n})\n\n// Lado AUTOR (escuchar acuses entrantes mientras la app está abierta):\nreceipts.start()\n\n// Lado del que ABRE (al importar contenido AJENO firmado):\nawait receipts.report({ toPubkey: parsed.publickey, url: sharedUrl, name: parsed.name })\n```\n\n- **Acumular (referidos)**: pasá `onReceipt(env)` para que tu app sume por acuse\n  fresco (además de la notificación). Para enlaces de invitación con tu pubkey\n  embebida usá `packPubkey(pubkey)` → token base64url para `#i=<token>`, y\n  `unpackPubkey(token)` del lado que abre (matchea byte a byte el ruteo del proxy).\n- **Identidad del que abre**: el sobre incluye **siempre** `from { pubkey, nick }`.\n- **Anti-spam**: `report` aplica throttle por `(toPubkey|url)` (default 24h).\n- **Propio**: `report` es no-op si el contenido es tuyo (`toPubkey === tu pubkey`).\n- **Contenido por defecto** (mismo en toda app, es/en): *\"Abrieron tu contenido\"* +\n  *«name» · nick*. Pásalo a medida con `render(env)`.\n- **Offline**: el contenido viaja por la **cola del proxy** (no por el push). El\n  push solo \"timbra\"; al reabrir la app, `identify()` drena la cola y aparece la\n  notificación con el enlace. El click usa `data.url` — tu SW\n  (`closer-click-push-sw.js`) ya navega a `event.notification.data.url`.\n\n> Apps de **partida en vivo** (chess/cuarenta comparten `#table=<token>` sin pubkey\n> del autor) no usan este acuse: el anfitrión ya ve el \"join\" por el canal. Pueden\n> enrutar ese evento por el mismo `createNotifications` para una UX uniforme.\n\n## Tema (CSS custom properties)\n\n```css\ncloser-click-notifications {\n  --ccn-bg: #12161d;\n  --ccn-accent: #2dd4bf;\n  --ccn-radius: 14px;\n}\n```\n\n`--ccn-bg`, `--ccn-bg-2..4`, `--ccn-border`, `--ccn-text`, `--ccn-muted`,\n`--ccn-accent`, `--ccn-accent-text`, `--ccn-danger`, `--ccn-gold`, `--ccn-radius`,\n`--ccn-font`.\n\n## Licencia\n\nMIT\n","readmeFilename":"README.md"}