{"_id":"@alteriom/webhook-client","_rev":"5-a200c202e3f46c0412108ebd9d7fa43a","name":"@alteriom/webhook-client","dist-tags":{"latest":"1.2.0"},"versions":{"0.1.0":{"name":"@alteriom/webhook-client","version":"0.1.0","keywords":["webhook","alteriom","github","typescript","api-client","openclaw"],"author":{"name":"Alteriom"},"license":"MIT","_id":"@alteriom/webhook-client@0.1.0","maintainers":[{"name":"sparck75","email":"dominic.lavoie@gmail.com"}],"homepage":"https://github.com/Alteriom/webhook-client#readme","bugs":{"url":"https://github.com/Alteriom/webhook-client/issues"},"dist":{"shasum":"0b71fe21811d1a3027b1df4e59a56d6e21232165","tarball":"https://registry.npmjs.org/@alteriom/webhook-client/-/webhook-client-0.1.0.tgz","fileCount":17,"integrity":"sha512-gA6YjsMtqBTQaVgc/BhTjLa8krc68zuj2AmQoiqJsLRfcNTqxfCqu/fPiluK4zn9heeWJE60adymUcHpVvRKmg==","signatures":[{"sig":"MEYCIQDwNWAVYVCyqe4ns1U0K2aW5VVtpu+yYDYY2GkkYo8YhAIhAIDA3Xcdn16uwS0lcUXSjjInLR77xnGkLbnQXlwDZldi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alteriom%2fwebhook-client@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":108209},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"43fa068c76c9e81a7a3301a1a1e0ff6f68194d09","scripts":{"lint":"eslint src/**/*.ts","test":"jest","build":"tsc","lint:fix":"eslint src/**/*.ts --fix","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"sparck75","email":"dominic.lavoie@gmail.com"},"repository":{"url":"git+https://github.com/Alteriom/webhook-client.git","type":"git"},"_npmVersion":"10.8.2","description":"Type-safe TypeScript client for Alteriom Webhook Connector","directories":{},"_nodeVersion":"20.20.0","dependencies":{"zod":"^3.24.1","axios":"^1.7.9"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.18.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.7.3","@types/jest":"^29.5.14","@types/node":"^22.10.5","@typescript-eslint/parser":"^8.20.0","@typescript-eslint/eslint-plugin":"^8.20.0"},"_npmOperationalInternal":{"tmp":"tmp/webhook-client_0.1.0_1772718642719_0.9494161747918628","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alteriom/webhook-client","version":"0.2.0","keywords":["webhook","alteriom","github","typescript","api-client","openclaw"],"author":{"name":"Alteriom"},"license":"MIT","_id":"@alteriom/webhook-client@0.2.0","maintainers":[{"name":"sparck75","email":"dominic.lavoie@gmail.com"}],"homepage":"https://github.com/Alteriom/webhook-client#readme","bugs":{"url":"https://github.com/Alteriom/webhook-client/issues"},"dist":{"shasum":"7d491b09a40469e92cd3acb4f75f9fb8d90d22d9","tarball":"https://registry.npmjs.org/@alteriom/webhook-client/-/webhook-client-0.2.0.tgz","fileCount":17,"integrity":"sha512-0Xt1GYg5JhbI+g+n8mz/4j8VtcV+vAcB8+8Clq2nrPF3RAECwqmdq8vFe51U1cNv8HP4H8XkuesgvkK5/3t2fg==","signatures":[{"sig":"MEYCIQCP00CKYQWilr8JsSCylGX/cHfUPX66f4n7/wcr1WELaAIhAOzHEfT0PCYI0RbBRWCjXb7gHrzabj90TlJg9Gju16yD","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alteriom%2fwebhook-client@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":110434},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"bccfb65cd1f4e7cc0ba31800fcd4930427202606","scripts":{"lint":"eslint src/**/*.ts","test":"jest","build":"tsc","lint:fix":"eslint src/**/*.ts --fix","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"sparck75","email":"dominic.lavoie@gmail.com"},"repository":{"url":"git+https://github.com/Alteriom/webhook-client.git","type":"git"},"_npmVersion":"10.8.2","description":"Type-safe TypeScript client for Alteriom Webhook Connector","directories":{},"_nodeVersion":"20.20.0","dependencies":{"zod":"^3.24.1","axios":"^1.7.9"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.18.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.7.3","@types/jest":"^29.5.14","@types/node":"^22.10.5","@typescript-eslint/parser":"^8.20.0","@typescript-eslint/eslint-plugin":"^8.20.0"},"_npmOperationalInternal":{"tmp":"tmp/webhook-client_0.2.0_1772917389816_0.9481799774647688","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@alteriom/webhook-client","version":"1.0.0","keywords":["webhook","alteriom","github","typescript","api-client","openclaw"],"author":{"name":"Alteriom"},"license":"MIT","_id":"@alteriom/webhook-client@1.0.0","maintainers":[{"name":"sparck75","email":"dominic.lavoie@gmail.com"}],"homepage":"https://github.com/Alteriom/webhook-client#readme","bugs":{"url":"https://github.com/Alteriom/webhook-client/issues"},"dist":{"shasum":"295c459d71e5058883ecdb122bc5ba2a73153550","tarball":"https://registry.npmjs.org/@alteriom/webhook-client/-/webhook-client-1.0.0.tgz","fileCount":17,"integrity":"sha512-Tzi8x5St2D3TQWiUeDn+6L0iKoYmQ7g4VYaaRKzH65kLCoXtOek0DgArjyJTwZrJbAx2Q9tmur8U/rZvf2v9rw==","signatures":[{"sig":"MEYCIQCtZ46D7SolCdPuSTX4WOiONgOkw4GpuTq/NC2VGvqYIwIhALgTKI/xJzaOwmnWcbevW3kGNQTP8I0+OufE/220be1/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alteriom%2fwebhook-client@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":119955},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.0.0"},"gitHead":"291d6434e014a172cf1f8895f56ab734a47d42de","scripts":{"lint":"eslint src/**/*.ts","test":"jest","build":"tsc","lint:fix":"eslint src/**/*.ts --fix","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"sparck75","email":"dominic.lavoie@gmail.com"},"repository":{"url":"git+https://github.com/Alteriom/webhook-client.git","type":"git"},"_npmVersion":"10.9.4","description":"Type-safe TypeScript client for Alteriom Webhook Connector","directories":{},"_nodeVersion":"22.22.1","dependencies":{"zod":"^3.24.1","axios":"^1.7.9"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.18.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.7.3","@types/jest":"^29.5.14","@types/node":"^22.10.5","@typescript-eslint/parser":"^8.20.0","@typescript-eslint/eslint-plugin":"^8.20.0"},"_npmOperationalInternal":{"tmp":"tmp/webhook-client_1.0.0_1774724192200_0.9625436932932641","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@alteriom/webhook-client","version":"1.1.0","keywords":["webhook","alteriom","github","typescript","api-client","openclaw"],"author":{"name":"Alteriom"},"license":"MIT","_id":"@alteriom/webhook-client@1.1.0","maintainers":[{"name":"sparck75","email":"dominic.lavoie@gmail.com"}],"homepage":"https://github.com/Alteriom/webhook-client#readme","bugs":{"url":"https://github.com/Alteriom/webhook-client/issues"},"dist":{"shasum":"8ad2eb96a0d601c3b3fbbfa1a49730660c61961a","tarball":"https://registry.npmjs.org/@alteriom/webhook-client/-/webhook-client-1.1.0.tgz","fileCount":21,"integrity":"sha512-5asPB9NdiUiB//t55IhmnlbLISe0OitorTOHaDcOjtWJh5/ReiojzAyXJo5yyW5Ei7CczPAtN1xONAbe8ofrBQ==","signatures":[{"sig":"MEYCIQCkWlg30iCDz+OfO4hw08ViJCGH7Mmck12WCLUp4QDHUgIhAOkvWyQTBqNA4yISqwUIYubeOgYw2TlLGoYjfw1i3TaF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alteriom%2fwebhook-client@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132347},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.0.0"},"gitHead":"392a6c372c958766277bce230833a2237352c52b","scripts":{"lint":"eslint src/**/*.ts","test":"jest","build":"tsc","lint:fix":"eslint src/**/*.ts --fix","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"sparck75","email":"dominic.lavoie@gmail.com"},"repository":{"url":"git+https://github.com/Alteriom/webhook-client.git","type":"git"},"_npmVersion":"10.9.4","description":"Type-safe TypeScript client for Alteriom Webhook Connector","directories":{},"_nodeVersion":"22.22.1","dependencies":{"zod":"^3.24.1","axios":"^1.7.9"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.18.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.7.3","@types/jest":"^29.5.14","@types/node":"^22.10.5","socket.io-client":"^4.8.3","@typescript-eslint/parser":"^8.20.0","@typescript-eslint/eslint-plugin":"^8.20.0"},"peerDependencies":{"socket.io-client":">=4.0.0"},"peerDependenciesMeta":{"socket.io-client":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/webhook-client_1.1.0_1775156819299_0.5419378616927302","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@alteriom/webhook-client","version":"1.2.0","description":"Type-safe TypeScript client for Alteriom Webhook Connector","engines":{"node":">=22.0.0"},"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","lint":"eslint src/**/*.ts","lint:fix":"eslint src/**/*.ts --fix","prepublishOnly":"npm run build && npm test"},"keywords":["webhook","alteriom","github","typescript","api-client","openclaw"],"author":{"name":"Alteriom"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/Alteriom/webhook-client.git"},"bugs":{"url":"https://github.com/Alteriom/webhook-client/issues"},"homepage":"https://github.com/Alteriom/webhook-client#readme","dependencies":{"axios":"^1.7.9","zod":"^3.24.1"},"peerDependencies":{"socket.io-client":">=4.0.0"},"peerDependenciesMeta":{"socket.io-client":{"optional":true}},"devDependencies":{"@types/jest":"^29.5.14","@types/node":"^22.10.5","@typescript-eslint/eslint-plugin":"^8.20.0","@typescript-eslint/parser":"^8.20.0","eslint":"^9.18.0","jest":"^29.7.0","socket.io-client":"^4.8.3","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.7.3"},"_id":"@alteriom/webhook-client@1.2.0","gitHead":"fc6ab667e4b2453f2c99d3a70c0147c597e5ba29","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-GiUtQd7NonSFoY/rpgeLpM5ujkZV6tmaji/cqHpRkAB6unoewDRQsDiZRdhRAPONjIp8sUAnZn78ZnLRAvw+4Q==","shasum":"812b5073f4654a9c335209c1728e47adb5d70c35","tarball":"https://registry.npmjs.org/@alteriom/webhook-client/-/webhook-client-1.2.0.tgz","fileCount":21,"unpackedSize":136629,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alteriom%2fwebhook-client@1.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCibypxMS+2KSVVSIeeSqqArQ8GXoOMN2HP3PjPw9aNkAIhAOpQIRF52NTxZFL4N1dS6LpzSs8duzP6bbqRcKlD5Ts4"}]},"_npmUser":{"name":"sparck75","email":"dominic.lavoie@gmail.com"},"directories":{},"maintainers":[{"name":"sparck75","email":"dominic.lavoie@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webhook-client_1.2.0_1775172131804_0.3695222573955488"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-05T13:50:42.571Z","modified":"2026-04-02T23:22:12.629Z","0.1.0":"2026-03-05T13:50:42.859Z","0.2.0":"2026-03-07T21:03:09.982Z","1.0.0":"2026-03-28T18:56:32.354Z","1.1.0":"2026-04-02T19:06:59.475Z","1.2.0":"2026-04-02T23:22:11.999Z"},"bugs":{"url":"https://github.com/Alteriom/webhook-client/issues"},"author":{"name":"Alteriom"},"license":"MIT","homepage":"https://github.com/Alteriom/webhook-client#readme","keywords":["webhook","alteriom","github","typescript","api-client","openclaw"],"repository":{"type":"git","url":"git+https://github.com/Alteriom/webhook-client.git"},"description":"Type-safe TypeScript client for Alteriom Webhook Connector","maintainers":[{"name":"sparck75","email":"dominic.lavoie@gmail.com"}],"readme":"# @alteriom/webhook-client\n\n> Type-safe TypeScript client for [Alteriom Webhook Connector](https://github.com/Alteriom/alteriom-webhook-connector)\n\n[![npm version](https://img.shields.io/npm/v/@alteriom/webhook-client)](https://www.npmjs.com/package/@alteriom/webhook-client)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Features\n\n- ✅ **Full TypeScript support** - Auto-generated types from OpenAPI spec\n- ✅ **REST API client** - All webhook-connector endpoints with retry logic\n- ✅ **Webhook receiver** - Secure HMAC-SHA256 signature verification\n- ✅ **Framework adapters** - Express, Fastify, Next.js support\n- ✅ **Rate limiting** - Token bucket algorithm (100 req/min default)\n- ✅ **Retry logic** - Exponential backoff with Retry-After support\n- ✅ **Type guards** - Runtime validation helpers\n- ✅ **Error classes** - Typed error responses\n- ✅ **Security** - Timing-safe signature comparison, replay prevention\n\n## Installation\n\n\\`\\`\\`bash\nnpm install @alteriom/webhook-client\n\\`\\`\\`\n\n## Quick Start\n\n### API Client\n\n\\`\\`\\`typescript\nimport { AlteriomWebhookClient } from '@alteriom/webhook-client';\n\nconst client = new AlteriomWebhookClient({\n  baseURL: 'https://webhook.alteriom.net',\n  apiKey: process.env.ALTERIOM_API_KEY!,\n});\n\n// List events\nconst events = await client.events.list({\n  event_type: 'pull_request',\n  status: 'completed',\n});\n\nconsole.log(`Found ${events.total} events`);\n\n// Get enrichment for an aggregate\nconst enrichment = await client.enrichment.enrich('aggregate-uuid');\nconsole.log('AI suggestions:', enrichment.suggested_actions);\n\\`\\`\\`\n\n### Webhook Receiver (Express)\n\n\\`\\`\\`typescript\nimport express from 'express';\nimport { expressReceiver } from '@alteriom/webhook-client';\n\nconst app = express();\napp.use(express.json());\n\napp.use('/webhook', expressReceiver({\n  secret: process.env.WEBHOOK_SECRET!,\n  onDelivery: async (delivery) => {\n    console.log('Received delivery:', delivery.subscription_id);\n\n    if (delivery.aggregate?.enrichment) {\n      // Act on AI suggestions\n      for (const action of delivery.aggregate.enrichment.suggested_actions) {\n        console.log('Suggested action:', action);\n        // Implement autonomous behavior here\n      }\n    }\n  },\n  onError: (error) => {\n    console.error('Webhook error:', error);\n  },\n}));\n\napp.listen(3000, () => console.log('Listening on :3000'));\n\\`\\`\\`\n\n### Webhook Receiver (Next.js)\n\n\\`\\`\\`typescript\n// pages/api/webhook.ts\nimport { nextjsReceiver } from '@alteriom/webhook-client';\n\nexport default nextjsReceiver({\n  secret: process.env.WEBHOOK_SECRET!,\n  onDelivery: async (delivery) => {\n    // Handle webhook delivery\n  },\n});\n\\`\\`\\`\n\n## Real-Time Events — WebSocket\n\nStream webhook events in real-time via the connector's Socket.IO server.\n\n**Requires:** `npm install socket.io-client` (optional peer dependency)\n\n```typescript\nimport { WebSocketClient } from '@alteriom/webhook-client';\n\nconst ws = new WebSocketClient({\n  url: 'https://webhook.alteriom.net',\n  apiKey: process.env.WEBHOOK_API_KEY!,\n  events: ['workflow_run', 'pull_request'],\n  repos: ['Alteriom/*', 'North-Relay/*'],\n});\n\nws.on('event', (event) => {\n  console.log(`${event.event}/${event.action} on ${event.repository}`);\n  console.log('Summary:', event.summary);\n});\n\nws.on('connected', ({ clientId }) => {\n  console.log('Connected as', clientId);\n});\n\nws.on('error', (err) => {\n  console.error('Connection error:', err.message);\n});\n\nws.connect();\n\n// Update filters without reconnecting\nws.updateSubscription({ events: ['workflow_run.completed'] });\n\n// Clean shutdown\nws.disconnect();\n```\n\n### WebSocket Features\n\n- **Auto-resubscribe:** Subscription filters are re-sent on every reconnect (server loses state on disconnect)\n- **Typed payloads:** `WebhookEventPayload` with `event`, `action`, `repository`, `summary`, `payload`\n- **Configurable filters:** Event types (`push`, `pull_request.opened`) and repo patterns (`Alteriom/*`)\n- **Lifecycle events:** `connected`, `disconnected`, `subscribed`, `error`\n- **Optional dependency:** `socket.io-client` is a peer dep — REST-only consumers don't need it\n\n## API Client\n\n### Configuration\n\n\\`\\`\\`typescript\nconst client = new AlteriomWebhookClient({\n  baseURL: 'https://webhook.alteriom.net',\n  apiKey: process.env.ALTERIOM_API_KEY!,\n  timeout: 30000, // Request timeout (default: 30s)\n  retry: {\n    maxRetries: 3, // Max retry attempts (default: 3)\n    backoffBase: 1000, // Base backoff ms (default: 1000)\n    backoffMultiplier: 2, // Backoff multiplier (default: 2)\n  },\n  rateLimit: {\n    maxRequests: 100, // Max requests per window (default: 100)\n    perMs: 60000, // Window size in ms (default: 60s)\n  },\n});\n\\`\\`\\`\n\n### Security Dashboard API (NEW in v0.1.0)\n\nGet a comprehensive view of security alerts across all repositories.\n\n\\`\\`\\`typescript\n// Get remediation queue (top 20 critical/high alerts)\nconst queue = await client.security.getRemediationQueue(20);\nqueue.forEach(alert => {\n  console.log(`${alert.type} alert #${alert.alert_number} in ${alert.repository}`);\n  console.log(`Severity: ${alert.severity}, Age: ${alert.age_days} days`);\n  console.log(`URL: ${alert.html_url}`);\n});\n\n// Get repository risk levels\nconst repos = await client.security.getRepositories();\nrepos.forEach(repo => {\n  console.log(`${repo.repository}: ${repo.risk_level} (score: ${repo.risk_score})`);\n  console.log(`  Dependabot: ${repo.alert_counts.dependabot}`);\n  console.log(`  Code Scanning: ${repo.alert_counts.code_scanning}`);\n  console.log(`  Secret Scanning: ${repo.alert_counts.secret_scanning}`);\n});\n\n// Get overall security badge counts\nconst badges = await client.security.getBadgeCounts();\nconsole.log('Dependabot:', badges.dependabot.total, 'open:', badges.dependabot.open);\nconsole.log('  Critical:', badges.dependabot.by_severity.critical);\nconsole.log('  High:', badges.dependabot.by_severity.high);\n\\`\\`\\`\n\n### Dependabot Alerts API (NEW in v0.1.0)\n\nMonitor and manage Dependabot vulnerability alerts.\n\n\\`\\`\\`typescript\n// List dependabot alerts with filters\nconst alerts = await client.dependabotAlerts.list({\n  repository: 'Alteriom/webhook-connector',\n  state: 'open',\n  severity: 'critical',\n  ecosystem: 'npm',\n  limit: 50,\n  offset: 0,\n});\n\nconsole.log(`Found ${alerts.total} alerts`);\nalerts.data.forEach(alert => {\n  console.log(`${alert.dependency_package}@${alert.vulnerable_version_range}`);\n  console.log(`  ${alert.vulnerability_severity}: ${alert.vulnerability_summary}`);\n  console.log(`  GHSA: ${alert.vulnerability_ghsa_id}`);\n  if (alert.patched_version) {\n    console.log(`  Fix: upgrade to ${alert.patched_version}`);\n  }\n});\n\n// Get single alert details\nconst alert = await client.dependabotAlerts.get('alert-uuid');\n\n// Get alert statistics\nconst stats = await client.dependabotAlerts.stats('Alteriom/webhook-connector');\nconsole.log('Total:', stats.total);\nconsole.log('By state:', stats.by_state);\nconsole.log('By severity:', stats.by_severity);\n\n// Export alerts to CSV (max 10,000 records)\nconst csv = await client.dependabotAlerts.export({\n  state: 'open',\n  severity: 'high,critical',\n});\n// Write CSV to file or send to user\n\\`\\`\\`\n\n### Code Scanning Alerts API (NEW in v0.1.0)\n\nManage code scanning security alerts (CodeQL, etc.).\n\n\\`\\`\\`typescript\n// List code scanning alerts\nconst alerts = await client.codeScanningAlerts.list({\n  repository: 'Alteriom/webhook-connector',\n  state: 'open',\n  severity: 'error',\n  limit: 50,\n});\n\nalerts.data.forEach(alert => {\n  console.log(`${alert.rule_id}: ${alert.rule_description}`);\n  console.log(`  Tool: ${alert.tool_name} ${alert.tool_version}`);\n  console.log(`  Instances: ${alert.instances_count}`);\n});\n\n// Get statistics\nconst stats = await client.codeScanningAlerts.stats();\n\n// Export to CSV\nconst csv = await client.codeScanningAlerts.export({ state: 'open' });\n\\`\\`\\`\n\n### Secret Scanning Alerts API (NEW in v0.1.0)\n\nMonitor exposed secrets in code.\n\n\\`\\`\\`typescript\n// List secret scanning alerts\nconst alerts = await client.secretScanningAlerts.list({\n  repository: 'Alteriom/webhook-connector',\n  state: 'open',\n});\n\nalerts.data.forEach(alert => {\n  console.log(`${alert.secret_type_display_name}`);\n  console.log(`  Locations: ${alert.locations_count}`);\n  console.log(`  Push protection bypassed: ${alert.push_protection_bypassed}`);\n});\n\n// Get statistics\nconst stats = await client.secretScanningAlerts.stats();\n\n// Export to CSV\nconst csv = await client.secretScanningAlerts.export({ state: 'open' });\n\\`\\`\\`\n\n### Security Advisories API (NEW in v0.1.0)\n\nManage GitHub Security Advisories and triage them.\n\n\\`\\`\\`typescript\n// List security advisories\nconst advisories = await client.securityAdvisories.list({\n  severity: 'critical',\n  limit: 50,\n});\n\nadvisories.data.forEach(advisory => {\n  console.log(`${advisory.ghsa_id}: ${advisory.summary}`);\n  console.log(`  Severity: ${advisory.severity} (CVSS: ${advisory.cvss_score})`);\n  console.log(`  Affected repos: ${advisory.affected_repositories.length}`);\n  console.log(`  Triage status: ${advisory.triage_status}`);\n});\n\n// Get single advisory\nconst advisory = await client.securityAdvisories.get('advisory-uuid');\n\n// Triage advisory (mark as not applicable or resolved)\nawait client.securityAdvisories.triage('advisory-uuid', {\n  status: 'not_applicable',\n  reason: 'Package not used in production',\n  notes: 'Only dev dependency, not exposed',\n});\n\n// Get statistics\nconst stats = await client.securityAdvisories.stats();\n\\`\\`\\`\n\n### Repositories API (NEW in v0.1.0)\n\nManage repository monitoring settings.\n\n\\`\\`\\`typescript\n// List all repositories\nconst repos = await client.repositories.list();\n\n// List only monitored repositories\nconst monitored = await client.repositories.list({ scan_enabled: true });\n\n// Get repository details\nconst repo = await client.repositories.get('Alteriom', 'webhook-connector');\nconsole.log('Scan enabled:', repo.scan_enabled);\nconsole.log('Language:', repo.language);\nconsole.log('Topics:', repo.topics);\n\n// Enable security scanning for repository\nawait client.repositories.update('Alteriom', 'webhook-connector', {\n  scan_enabled: true,\n});\n\n// Disable security scanning\nawait client.repositories.update('Alteriom', 'old-repo', {\n  scan_enabled: false,\n});\n\n// Remove repository from system\nawait client.repositories.delete('Alteriom', 'archived-repo');\n\\`\\`\\`\n\n### HTTP Subscribers API (NEW in v0.1.0)\n\nManage HTTP webhook subscribers.\n\n\\`\\`\\`typescript\n// List HTTP subscribers\nconst subscribers = await client.httpSubscribers.list();\nsubscribers.forEach(sub => {\n  console.log(`${sub.name}: ${sub.url}`);\n  console.log(`  Events: ${sub.events.join(', ')}`);\n  console.log(`  Stats: ${sub.delivery_stats.successful_deliveries}/${sub.delivery_stats.total_deliveries} successful`);\n});\n\n// Create HTTP subscriber\nconst subscriber = await client.httpSubscribers.create({\n  name: 'Production Webhook',\n  url: 'https://api.example.com/webhooks',\n  secret: 'my-webhook-secret',\n  events: ['dependabot_alert', 'code_scanning_alert'],\n  filters: {\n    repositories: ['Alteriom/*'],\n    severity: ['critical', 'high'],\n  },\n});\n\n// Update subscriber\nawait client.httpSubscribers.update(subscriber.id, {\n  enabled: false,\n});\n\n// Test webhook delivery\nconst result = await client.httpSubscribers.test(subscriber.id);\nif (result.success) {\n  console.log(`Test successful: ${result.status_code} in ${result.latency_ms}ms`);\n} else {\n  console.error(`Test failed: ${result.error}`);\n}\n\n// Delete subscriber\nawait client.httpSubscribers.delete(subscriber.id);\n\\`\\`\\`\n\n### API Keys API (NEW in v0.1.0)\n\nManage API keys with auto-rotation support.\n\n\\`\\`\\`typescript\n// List API keys\nconst keys = await client.apiKeys.list();\nkeys.forEach(key => {\n  console.log(`${key.name} (${key.key_prefix}...)`);\n  console.log(`  Scopes: ${key.scopes.join(', ')}`);\n  console.log(`  Last used: ${key.last_used_at || 'never'}`);\n  console.log(`  Auto-rotate: ${key.auto_rotate} (every ${key.rotation_days} days)`);\n});\n\n// Create API key with auto-rotation\nconst { key, secret } = await client.apiKeys.create({\n  name: 'Production Key',\n  description: 'Main production API key',\n  scopes: ['read', 'write'],\n  expires_at: '2027-03-05T00:00:00Z', // Optional expiration\n  auto_rotate: true,\n  rotation_days: 90, // Rotate every 90 days\n});\n\nconsole.log('New API key:', secret); // Save this securely!\n\n// Update key settings\nawait client.apiKeys.update(key.id, {\n  description: 'Updated description',\n  auto_rotate: false,\n});\n\n// Manually rotate key\nconst result = await client.apiKeys.rotate(key.id);\nconsole.log('New key:', result.new_key);\nconsole.log('Expires at:', result.expires_at);\n\n// Deactivate key\nawait client.apiKeys.update(key.id, { active: false });\n\n// Delete key\nawait client.apiKeys.delete(key.id);\n\\`\\`\\`\n\n### Audit Logs API (NEW in v0.1.0)\n\nTrack all API key usage and configuration changes.\n\n\\`\\`\\`typescript\n// List audit events\nconst logs = await client.audit.list({ limit: 50, offset: 0 });\nlogs.data.forEach(event => {\n  console.log(`[${event.created_at}] ${event.actor} ${event.action} ${event.resource_type}`);\n  console.log(`  Details:`, event.details);\n});\n\n// Get single audit event\nconst event = await client.audit.get('event-uuid');\n\\`\\`\\`\n\n### Health API (NEW in v0.1.0)\n\nMonitor system health and configuration.\n\n\\`\\`\\`typescript\n// Get system health status\nconst health = await client.health.status();\nconsole.log('Status:', health.status); // healthy | degraded | unhealthy\nconsole.log('Uptime:', health.uptime_seconds, 'seconds');\nconsole.log('Checks:', health.checks);\n\n// Get handler configurations\nconst handlers = await client.health.handlers();\nhandlers.forEach(handler => {\n  console.log(`${handler.event_type}: ${handler.handler_name} (priority: ${handler.priority})`);\n});\n\n// Get pending events summary\nconst pending = await client.health.pendingEvents();\nconsole.log('Total pending:', pending.total);\nconsole.log('By status:', pending.by_status);\nconsole.log('Oldest pending:', pending.oldest_pending_at);\n\\`\\`\\`\n\n### Dashboard API (NEW in v0.1.0)\n\nGet dashboard metrics and time-series data.\n\n\\`\\`\\`typescript\n// Get dashboard statistics\nconst stats = await client.dashboard.stats();\nconsole.log('Total events:', stats.total_events);\nconsole.log('Total deliveries:', stats.total_deliveries);\nconsole.log('Active subscribers:', stats.active_subscribers);\nconsole.log('Delivery success rate:', stats.delivery_success_rate * 100, '%');\nconsole.log('Avg latency:', stats.avg_latency_ms, 'ms');\n\n// Top repositories\nstats.top_repositories.forEach(repo => {\n  console.log(`${repo.repository}: ${repo.event_count} events`);\n});\n\n// Get time-series data\nconst timeseries = await client.dashboard.timeSeries('events', '1h');\ntimeseries.forEach(point => {\n  console.log(`${point.timestamp}: ${point.value}`);\n});\n\\`\\`\\`\n\n### Pipelines API (NEW in v0.1.0)\n\nMonitor CI/CD pipeline statuses.\n\n\\`\\`\\`typescript\n// List all pipeline statuses\nconst pipelines = await client.pipelines.list();\n\n// List pipelines for specific repository\nconst repoPipelines = await client.pipelines.list('Alteriom/webhook-connector');\n\nrepoPipelines.forEach(pipeline => {\n  console.log(`${pipeline.workflow_name} #${pipeline.run_number}: ${pipeline.status}`);\n  console.log(`  Branch: ${pipeline.branch}`);\n  console.log(`  Commit: ${pipeline.commit_sha.slice(0, 7)} - ${pipeline.commit_message}`);\n  console.log(`  Duration: ${pipeline.duration_seconds}s`);\n});\n\n// Get pipelines for owner/repo\nconst specific = await client.pipelines.get('Alteriom', 'webhook-connector');\n\\`\\`\\`\n\n### Query Logs API (NEW in v0.1.0)\n\nTrack API usage and query logs.\n\n\\`\\`\\`typescript\n// List query logs\nconst logs = await client.queryLogs.list({ limit: 50, offset: 0 });\nlogs.data.forEach(log => {\n  console.log(`[${log.created_at}] ${log.method} ${log.endpoint}`);\n  console.log(`  API Key: ${log.api_key_name}`);\n  console.log(`  Response: ${log.response_code} (${log.latency_ms}ms)`);\n  console.log(`  Results: ${log.result_count}`);\n});\n\\`\\`\\`\n\n### Agent Subscriptions API (NEW in v1.1.0)\n\nAgent subscriptions provide fine-grained filtering per agent — subscribe only to the repos and event types you care about.\n\n\\`\\`\\`typescript\n// Create a CI monitoring subscription for Jarvis\nconst subscription = await client.agentSubscriptions.create({\n  agent_name: 'jarvis-ci-monitor',\n  repositories: [\n    'North-Relay/northrelay-platform',\n    'Alteriom/alteriom-dev-ops',\n    'Alteriom/alteriom-webhook-connector'\n  ],\n  event_types: ['workflow_run', 'workflow_job', 'deployment_status'],\n  delivery_mode: 'realtime',\n  webhook_url: 'https://your-agent.example.com/webhook',\n});\n\n// List subscriptions\nconst { subscriptions } = await client.agentSubscriptions.list();\n\n// Update subscription (add a repo)\nawait client.agentSubscriptions.update(subscription.id, {\n  filters: { repositories: ['North-Relay/northrelay-platform', 'Alteriom/new-repo'] },\n});\n\n// Get delivery stats\nconst stats = await client.agentSubscriptions.stats(subscription.id);\nconsole.log(`Success rate: ${stats.success_rate}%`);\n\n// Delete subscription\nawait client.agentSubscriptions.delete(subscription.id);\n\\`\\`\\`\n\n#### On-Demand Polling\n\nFor `on_demand` subscriptions, use `poll()` to fetch new events matching your subscription's filters:\n\n\\`\\`\\`typescript\n// Simple polling — reads repo/event filters from the subscription automatically\nconst events = await client.agentSubscriptions.poll(\n  'acfdd1a3-e29c-451c-8db9-be8e76918c4f',\n  { since: lastCheckTimestamp }\n);\n\nconsole.log(`Found ${events.length} new events`);\nevents.forEach(e => {\n  console.log(`${e.aggregate_type} on ${e.repository}: ${e.summary?.conclusion || e.summary?.status}`);\n});\n\n// Update your timestamp for next poll\nlastCheckTimestamp = new Date().toISOString();\n\\`\\`\\`\n\n### Events API\n\n\\`\\`\\`typescript\n// List events with filters\nconst events = await client.events.list({\n  page: 1,\n  limit: 50,\n  event_type: 'pull_request',\n  status: 'completed',\n  repository: 'Alteriom/*',\n  sender: 'sparck75',\n  search: 'github_delivery_id',\n  from: '2026-02-01T00:00:00Z',\n  to: '2026-02-11T23:59:59Z',\n});\n\n// Get single event\nconst event = await client.events.get('event-uuid');\n\\`\\`\\`\n\n### Aggregates API\n\n\\`\\`\\`typescript\n// List aggregates\nconst aggregates = await client.aggregates.list({ page: 1, limit: 50 });\n\n// Note: aggregates.get(id) removed in v0.1.0 - endpoint doesn't exist\n// Use list and filter instead\nconst aggregate = aggregates.data.find(a => a.entity_id === 'some-id');\n\\`\\`\\`\n\n### TypedAggregate — Type Narrowing (NEW in v1.0.0)\n\n`aggregate_type` is now a union of 22 literal types instead of `string`. TypeScript narrows the `summary` shape automatically based on the type discriminant, giving you full type safety on aggregate data.\n\n\\`\\`\\`typescript\nconst { data } = await client.aggregates.list({\n  aggregate_type: 'workflow_run',\n  branch: 'main',\n  conclusion: 'failure',\n  limit: 5,\n});\n\nfor (const agg of data) {\n  // TypeScript narrows summary type based on aggregate_type\n  if (agg.aggregate_type === 'workflow_run') {\n    console.log(`${agg.summary.workflow_name} failed on ${agg.summary.branch}`);\n  }\n}\n\\`\\`\\`\n\nNew filter parameters for `aggregates.list()`:\n\n| Param | Type | Description |\n|-------|------|-------------|\n| `branch` | `string` | Filter by branch name (e.g. `'main'`, `'feature/*'`) |\n| `conclusion` | `string` | Filter by workflow conclusion (`'success'`, `'failure'`, `'cancelled'`, etc.) |\n| `workflow_name` | `string` | Filter by workflow display name |\n\n### Python HMAC Signature Verification\n\nFor teams integrating the webhook server from Python without a dedicated SDK:\n\n\\`\\`\\`python\nimport hmac, hashlib, time\n\ndef verify_signature(body: bytes, signature: str, timestamp: str, secret: str, tolerance: int = 300) -> bool:\n    age = abs(int(time.time()) - int(timestamp))\n    if age > tolerance:\n        return False\n    data = f'{timestamp}.{body.decode()}'\n    expected = 'sha256=' + hmac.new(secret.encode(), data.encode(), hashlib.sha256).hexdigest()\n    return hmac.compare_digest(expected, signature)\n\\`\\`\\`\n\n### Enrichment API\n\n\\`\\`\\`typescript\n// Trigger AI enrichment (GPT-4 analysis)\nconst enrichment = await client.enrichment.enrich('aggregate-uuid');\n\nconsole.log('Summary:', enrichment.summary);\nconsole.log('Risk:', enrichment.risk_level);\nconsole.log('Security concerns:', enrichment.security_concerns);\nconsole.log('Suggested actions:', enrichment.suggested_actions);\nconsole.log('Cost:', `$${enrichment.cost_usd?.toFixed(4)}`);\n\\`\\`\\`\n\n### Deliveries API\n\n\\`\\`\\`typescript\n// List deliveries\nconst deliveries = await client.deliveries.list({ limit: 50 });\n\n// Get delivery statistics\nconst stats = await client.deliveries.stats();\n\\`\\`\\`\n\n### Subscribers API\n\n\\`\\`\\`typescript\n// List subscriptions\nconst subscribers = await client.subscribers.list();\n\n// Create subscription\nconst subscription = await client.subscribers.create({\n  name: 'my-agent',\n  url: 'https://my-agent.com/webhook',\n  secret: 'my-webhook-secret',\n  events: ['pull_request', 'issues'],\n  filters: {\n    repositories: ['Alteriom/*'],\n    senders: ['sparck75'],\n  },\n});\n\n// Update subscription\nawait client.subscribers.update('sub-uuid', {\n  enabled: false,\n});\n\n// Delete subscription\nawait client.subscribers.delete('sub-uuid');\n\\`\\`\\`\n\n## Webhook Receiver\n\n### Security Features\n\n✅ **HMAC-SHA256 Signature Verification** - Timing-safe comparison  \n✅ **Replay Attack Prevention** - Reject webhooks older than 5 minutes  \n✅ **Duplicate Detection** - Cache processed deliveries for 1 hour  \n✅ **Payload Size Limit** - Reject payloads > 10 MB  \n\n### Configuration\n\n\\`\\`\\`typescript\nconst receiver = webhookReceiver({\n  secret: process.env.WEBHOOK_SECRET!, // Required\n  onDelivery: async (delivery) => { /* ... */ }, // Required\n  onSuccess: (delivery) => { /* Optional */ },\n  onError: (error) => { /* Optional */ },\n  maxAge: 300000, // Max webhook age in ms (default: 5 min)\n  maxPayloadSize: 10 * 1024 * 1024, // Max payload bytes (default: 10 MB)\n  skipVerification: false, // Skip signature check (dev only)\n  logger: console, // Optional logger (debug, error methods)\n});\n\\`\\`\\`\n\n### Testing Webhooks\n\nUse `generateWebhookSignature()` to create valid test requests:\n\n\\`\\`\\`typescript\nimport { generateWebhookSignature } from '@alteriom/webhook-client';\n\nconst payload = {\n  subscription_id: 'test-sub',\n  delivery_mode: 'aggregate',\n  aggregate: { /* ... */ },\n  delivered_at: new Date().toISOString(),\n};\n\nconst { signature, timestamp } = generateWebhookSignature(\n  payload,\n  'my-webhook-secret'\n);\n\n// Send test request\nawait fetch('http://localhost:3000/webhook', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json',\n    'X-Connector-Signature-256': signature,\n    'X-Connector-Timestamp': timestamp,\n  },\n  body: JSON.stringify(payload),\n});\n\\`\\`\\`\n\n## TypeScript Types\n\nAll types are exported from the main entry point:\n\n\\`\\`\\`typescript\nimport type {\n  WebhookEvent,\n  EventAggregate,\n  Enrichment,\n  SubscriptionDelivery,\n  Subscriber,\n  Delivery,\n  EventStatus,\n  RiskLevel,\n  DeliveryStatus,\n} from '@alteriom/webhook-client';\n\\`\\`\\`\n\n### Type Guards\n\nRuntime validation helpers:\n\n\\`\\`\\`typescript\nimport { isEnrichment, isSubscriptionDelivery } from '@alteriom/webhook-client';\n\nif (isEnrichment(obj)) {\n  // obj is typed as Enrichment\n  console.log(obj.suggested_actions);\n}\n\nif (isSubscriptionDelivery(obj)) {\n  // obj is typed as SubscriptionDelivery\n  console.log(obj.aggregate.enrichment);\n}\n\\`\\`\\`\n\n## Error Handling\n\n\\`\\`\\`typescript\nimport {\n  ApiError,\n  RateLimitError,\n  ValidationError,\n  SignatureVerificationError,\n  WebhookExpiredError,\n} from '@alteriom/webhook-client';\n\ntry {\n  const events = await client.events.list();\n} catch (error) {\n  if (error instanceof RateLimitError) {\n    console.log(`Rate limited. Retry after ${error.retryAfter}s`);\n    console.log(`Limit: ${error.limit}, Remaining: ${error.remaining}`);\n  } else if (error instanceof ApiError) {\n    console.log(`API error: ${error.message} (status: ${error.status})`);\n    console.log('Details:', error.details);\n  }\n}\n\\`\\`\\`\n\n## Examples\n\nSee the `examples/` directory for complete working examples:\n\n- **Express.js** - Simple webhook receiver\n- **Fastify** - High-performance webhook receiver\n- **Next.js** - API route webhook handler\n- **Friday Agent** - Full OpenClaw agent integration\n\n## Migration Guide\n\n### Before (Manual Implementation)\n\n\\`\\`\\`typescript\n// 200+ lines of manual webhook handling\nimport express from 'express';\nimport crypto from 'crypto';\n\nconst app = express();\n\napp.post('/webhook', (req, res) => {\n  // Manual signature verification (20 lines)\n  // Manual timestamp validation (10 lines)\n  // Manual error handling (30 lines)\n  // Manual type casting (unsafe)\n  // Process webhook (90 lines)\n  \n  res.status(200).send('ok');\n});\n\\`\\`\\`\n\n### After (With Package)\n\n\\`\\`\\`typescript\n// 10 lines total\nimport express from 'express';\nimport { expressReceiver } from '@alteriom/webhook-client';\n\nconst app = express();\n\napp.use('/webhook', expressReceiver({\n  secret: process.env.WEBHOOK_SECRET!,\n  onDelivery: async (delivery) => {\n    // Type-safe, secure, validated ✅\n  },\n}));\n\\`\\`\\`\n\n**Reduction:** 200+ lines → 10 lines (95% less code)\n\n## Development\n\n\\`\\`\\`bash\n# Install dependencies\nnpm install\n\n# Build TypeScript\nnpm run build\n\n# Run tests\nnpm test\n\n# Run linter\nnpm run lint\n\\`\\`\\`\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT © [Alteriom](https://github.com/Alteriom)\n\n## Links\n\n- **Documentation:** [https://docs.alteriom.net](https://docs.alteriom.net)\n- **GitHub:** [https://github.com/Alteriom/webhook-client](https://github.com/Alteriom/webhook-client)\n- **NPM:** [https://www.npmjs.com/package/@alteriom/webhook-client](https://www.npmjs.com/package/@alteriom/webhook-client)\n- **Webhook Connector:** [https://github.com/Alteriom/alteriom-webhook-connector](https://github.com/Alteriom/alteriom-webhook-connector)\n\n## Support\n\n- **Issues:** [GitHub Issues](https://github.com/Alteriom/webhook-client/issues)\n- **Discord:** [OpenClaw Community](https://discord.gg/clawd)\n\n---\n\n**Built for [OpenClaw](https://openclaw.ai) agents** 🐾\n","readmeFilename":"README.md"}