{"_id":"@ahm-labs/nanolog","name":"@ahm-labs/nanolog","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@ahm-labs/nanolog","version":"1.0.0","description":"Official TypeScript SDK and React components for NanoLog — the zero-bloat, PII-safe changelog, public roadmap, and user feedback widget with Shadow DOM isolation.","author":{"name":"AHM Labs","email":"dev@ahm-labs.com","url":"https://ahm-labs.com"},"license":"MIT","keywords":["nanolog","changelog","roadmap","user-feedback","in-app-announcements","feature-requests","nps","react-changelog","nextjs-changelog","shadow-dom","pii-redaction","product-updates"],"publishConfig":{"access":"public"},"homepage":"https://nanolog.dev","repository":{"type":"git","url":"git+https://github.com/AHM-Labs/nanoLogNext.git","directory":"sdk"},"bugs":{"url":"https://github.com/AHM-Labs/nanoLogNext/issues"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","require":"./dist/react/index.cjs"}},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"peerDependencies":{"react":">=16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0","react-dom":">=16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true}},"devDependencies":{"@types/node":"^22.13.0","@types/react":"^19.0.8","@types/react-dom":"^19.0.3","react":"^19.0.0","react-dom":"^19.0.0","tsup":"^8.3.6","typescript":"^5.7.3"},"_id":"@ahm-labs/nanolog@1.0.0","gitHead":"10aa91d450eb9acfd7a5d687aeeaf05993a568dc","_nodeVersion":"22.12.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-dFWXVyBkSi7F8di3Hb46cpnq3xMNKBPnVHbA1wK7INZmq0PojkaTPrkrsPcBvMb4jl/aOc70BADUpYJDRKh+xg==","shasum":"90a57943cb95a4a1789f8cc9d8b4469024cdd976","tarball":"https://registry.npmjs.org/@ahm-labs/nanolog/-/nanolog-1.0.0.tgz","fileCount":19,"unpackedSize":80102,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDRFROOZUcbHays3BrW1OpzLDm84O5ucL/w23SEEdc+8gIgZ7wLdJWfhEMnn4YHrKfzY3oUvNVi1WzK6Un1sPXS9/E="}]},"_npmUser":{"name":"ahmlabs","email":"aaron@ahm-labs.com"},"directories":{},"maintainers":[{"name":"ahmlabs","email":"aaron@ahm-labs.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nanolog_1.0.0_1789213897892_0.9186928726907513"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-12T11:51:37.628Z","1.0.0":"2026-09-12T11:51:38.028Z","modified":"2026-09-12T11:51:38.361Z"},"maintainers":[{"name":"ahmlabs","email":"aaron@ahm-labs.com"}],"description":"Official TypeScript SDK and React components for NanoLog — the zero-bloat, PII-safe changelog, public roadmap, and user feedback widget with Shadow DOM isolation.","homepage":"https://nanolog.dev","keywords":["nanolog","changelog","roadmap","user-feedback","in-app-announcements","feature-requests","nps","react-changelog","nextjs-changelog","shadow-dom","pii-redaction","product-updates"],"repository":{"type":"git","url":"git+https://github.com/AHM-Labs/nanoLogNext.git","directory":"sdk"},"author":{"name":"AHM Labs","email":"dev@ahm-labs.com","url":"https://ahm-labs.com"},"bugs":{"url":"https://github.com/AHM-Labs/nanoLogNext/issues"},"license":"MIT","readme":"# @ahm-labs/nanolog 🚀\n\n> Official TypeScript SDK and React hooks for **NanoLog** — the zero-bloat, PII-safe 3-in-1 product communication suite (Changelogs, Public Roadmaps, and Contextual User Feedback with Shadow DOM style isolation).\n\n[![npm version](https://img.shields.io/npm/v/@ahm-labs/nanolog.svg)](https://www.npmjs.com/package/@ahm-labs/nanolog)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@ahm-labs/nanolog)](https://bundlephobia.com/package/@ahm-labs/nanolog)\n\n---\n\n## Features\n\n- ⚡ **Sub-20KB Brotli Core**: Native Web Component architecture ensures zero render blocking and 100/100 Core Web Vitals.\n- 🔒 **Shadow DOM Style Isolation**: Widget styles never leak out, and host application resets (like Tailwind or Bootstrap) cannot bleed in.\n- 🛡️ **Client-Side PII Redaction**: Automatic heuristic scrubbing of passwords, emails, credit cards, and tokens before user feedback is transmitted.\n- 🔑 **Cryptographic HMAC Security**: Server-signed identity tokens prevent client-side context spoofing and ballot stuffing.\n- ⚛️ **First-Class React & Next.js Support**: Declarative `<NanoLog />` component, `useNanoLog()` hook, and `<NanoLogTrigger />` component.\n- 🌐 **Universal Runtime**: Works seamlessly in Next.js (App & Pages Router), React, Vite, Astro, Remix, Vue, and Vanilla JS.\n- 📦 **Dual ESM & CJS**: Full TypeScript definitions (`.d.ts`) included out of the box.\n\n---\n\n## Installation\n\n```bash\nnpm install @ahm-labs/nanolog\n# or\npnpm add @ahm-labs/nanolog\n# or\nyarn add @ahm-labs/nanolog\n```\n\n---\n\n## Quickstart\n\n### 1. Next.js 14/15 App Router (`@ahm-labs/nanolog/react`)\n\nCreate a client-side wrapper component:\n\n```tsx\n// components/NanoLogWrapper.tsx\n'use client';\n\nimport { NanoLog } from '@ahm-labs/nanolog/react';\n\nexport function NanoLogWrapper({ user }: { user?: { id: string; role: string; plan: string } }) {\n  return (\n    <NanoLog\n      appId=\"0821139e-8d66-4878-bfaf-4e47865b4c88\"\n      context={{\n        userId: user?.id,\n        role: user?.role || 'member',\n        tier: user?.plan || 'free'\n      }}\n    />\n  );\n}\n```\n\nThen drop it into your root `app/layout.tsx`:\n\n```tsx\nimport { NanoLogWrapper } from '@/components/NanoLogWrapper';\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    <html lang=\"en\">\n      <body>\n        {children}\n        <NanoLogWrapper />\n      </body>\n    </html>\n  );\n}\n```\n\n---\n\n### 2. React Hook (`useNanoLog`)\n\nFor custom launchers, menu items, or header buttons:\n\n```tsx\nimport React from 'react';\nimport { useNanoLog, NanoLogTrigger } from '@ahm-labs/nanolog/react';\n\nexport function AppHeader({ currentUser }) {\n  const { isReady, open, close, toggle } = useNanoLog({\n    appId: '0821139e-8d66-4878-bfaf-4e47865b4c88',\n    context: {\n      role: currentUser.role,\n      tier: currentUser.subscriptionTier\n    }\n  });\n\n  return (\n    <header className=\"navbar\">\n      <h1>My SaaS</h1>\n      \n      {/* Option A: Using the hook directly */}\n      <button onClick={open} disabled={!isReady}>\n        ⚡ What's New\n      </button>\n\n      {/* Option B: Using the convenience trigger component */}\n      <NanoLogTrigger className=\"btn-secondary\">\n        Feedback &amp; Roadmap\n      </NanoLogTrigger>\n    </header>\n  );\n}\n```\n\n---\n\n### 3. Vanilla JavaScript / Single-Page Apps\n\n```typescript\nimport { initNanoLog, openNanoLog } from '@ahm-labs/nanolog';\n\n// Asynchronously load and initialize\nawait initNanoLog({\n  appId: '0821139e-8d66-4878-bfaf-4e47865b4c88',\n  context: {\n    role: 'admin',\n    tier: 'enterprise',\n    tenantId: 'acme_corp'\n  }\n});\n\n// Programmatic controls\ndocument.getElementById('whats-new-btn').addEventListener('click', () => {\n  openNanoLog();\n});\n```\n\n---\n\n## Cryptographic HMAC Security (Anti-Spoofing)\n\nTo prevent users from modifying client-side context (e.g. claiming to be an `enterprise` admin to view private release notes):\n\n1. **Sign the context on your backend:**\n\n```typescript\n// Node.js Server Action or API Route\nimport crypto from 'crypto';\n\nexport function getSignedNanoLogContext(user) {\n  const context = {\n    userId: user.id,\n    role: user.role,\n    tier: user.plan\n  };\n\n  // Deterministically sort keys and generate HMAC SHA-256\n  const serialized = JSON.stringify(context, Object.keys(context).sort());\n  const signature = crypto\n    .createHmac('sha256', process.env.NANOLOG_HMAC_SECRET!)\n    .update(serialized)\n    .digest('hex');\n\n  return { context, signature };\n}\n```\n\n2. **Pass the signature to `<NanoLog />` or `initNanoLog()`:**\n\n```tsx\n<NanoLog\n  appId=\"0821139e-8d66-4878-bfaf-4e47865b4c88\"\n  context={signedData.context}\n  signature={signedData.signature}\n/>\n```\n\n---\n\n## API Reference\n\n### Core (`@ahm-labs/nanolog`)\n\n| Function | Return Type | Description |\n| :--- | :--- | :--- |\n| `initNanoLog(config, options?)` | `Promise<NanoLogInstance>` | Asynchronously loads the script and initializes the widget. |\n| `loadNanoLog(options?)` | `Promise<NanoLogInstance>` | Loads the widget script into `document.head` with single-injection guarantee. |\n| `openNanoLog()` | `void` | Programmatically opens the widget drawer. |\n| `closeNanoLog()` | `void` | Programmatically closes the widget drawer. |\n| `toggleNanoLog()` | `void` | Toggles the widget open/closed. |\n| `refreshNanoLog()` | `void` | Refetches posts and roadmap updates from the server. |\n| `isNanoLogLoaded()` | `boolean` | Checks if `window.NanoLog` is initialized. |\n| `getNanoLogInstance()` | `NanoLogInstance \\| null` | Returns the underlying `window.NanoLog` instance. |\n\n### React (`@ahm-labs/nanolog/react`)\n\n| Component / Hook | Type | Description |\n| :--- | :--- | :--- |\n| `<NanoLog />` | React Component | Declarative wrapper that handles SSR, mounts widget, and keeps context synchronized. |\n| `<NanoLogTrigger />` | React Component | Convenience button wrapper that executes `open()` on click. |\n| `useNanoLog(options)` | React Hook | Hook returning `{ isReady, isLoading, error, open, close, toggle, refresh, instance }`. |\n\n---\n\n## TypeScript Types\n\n```typescript\nexport interface NanoLogConfig {\n  appId: string;\n  context?: WidgetContext;\n  signature?: string;\n  apiBase?: string;\n  debug?: boolean;\n  previewConfig?: PreviewConfig;\n  uniqueUserIdKey?: string;\n}\n\nexport interface WidgetContext {\n  role?: string;\n  tier?: string;\n  userId?: string;\n  email?: string;\n  tenantId?: string;\n  betaTester?: boolean;\n  [key: string]: any;\n}\n```\n\n---\n\n## License\n\nMIT © [AHM Labs](https://ahm-labs.com)\n","readmeFilename":"README.md","_rev":"1-d046c12d5168212eaa30c50ee1a151d8"}