{"_id":"@apiclient.xyz/peeringdb","name":"@apiclient.xyz/peeringdb","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.1":{"name":"@apiclient.xyz/peeringdb","version":"1.0.1","private":false,"description":"an unofficial package for the peeringdb API","main":"dist_ts/index.js","typings":"dist_ts/index.d.ts","type":"module","author":{"name":"Task Venture Capital GmbH"},"license":"MIT","repository":{"type":"git","url":"https://code.foss.global/apiclient.xyz/peeringdb.git"},"bugs":{"url":"https://code.foss.global/apiclient.xyz/peeringdb/issues"},"homepage":"https://code.foss.global/apiclient.xyz/peeringdb#readme","dependencies":{"@push.rocks/smartlog":"^3.0.0","@push.rocks/smartrequest":"^2.0.0"},"devDependencies":{"@git.zone/tsbuild":"^2.1.25","@git.zone/tsbundle":"^2.0.5","@git.zone/tstest":"^2.7.0","@push.rocks/qenv":"^6.0.0","@types/node":"^24.10.1"},"scripts":{"test":"(tstest test/ --verbose)","build":"(tsbuild --web --allowimplicitany)","buildDocs":"(tsdoc)"},"_id":"@apiclient.xyz/peeringdb@1.0.1","_integrity":"sha512-643M/wxzxJuTqoenaO9Ar0nMUskgAFr3HuWPorDPnwqHkXLD9b2jPsLX/LD2vciHlQjW1hNrtl+wwzv51LvNeg==","_resolved":"/tmp/8db69cf4796d48ceb97ea6dfb28370ea/apiclient.xyz-peeringdb-1.0.1.tgz","_from":"file:apiclient.xyz-peeringdb-1.0.1.tgz","_nodeVersion":"23.8.0","_npmVersion":"11.3.0","dist":{"integrity":"sha512-643M/wxzxJuTqoenaO9Ar0nMUskgAFr3HuWPorDPnwqHkXLD9b2jPsLX/LD2vciHlQjW1hNrtl+wwzv51LvNeg==","shasum":"91760463e44c6d69ecbe498c19185bde5a10a455","tarball":"https://registry.npmjs.org/@apiclient.xyz/peeringdb/-/peeringdb-1.0.1.tgz","fileCount":79,"unpackedSize":163705,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEQagUtVSyF8Ht2mR111iBAROiF/oZAxFE5bJMbTZWSyAiEA0/Cmowyd5Zc5PrEu/R2tWrOffafqxg0nDrWqHo90B18="}]},"_npmUser":{"name":"lossless","email":"hello@lossless.com"},"directories":{},"maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/peeringdb_1.0.1_1763653780655_0.630792439240289"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-20T15:49:40.550Z","1.0.1":"2025-11-20T15:49:40.856Z","modified":"2025-11-20T15:49:41.133Z"},"maintainers":[{"name":"lossless","email":"hello@lossless.com"}],"description":"an unofficial package for the peeringdb API","homepage":"https://code.foss.global/apiclient.xyz/peeringdb#readme","repository":{"type":"git","url":"https://code.foss.global/apiclient.xyz/peeringdb.git"},"author":{"name":"Task Venture Capital GmbH"},"bugs":{"url":"https://code.foss.global/apiclient.xyz/peeringdb/issues"},"license":"MIT","readme":"# @apiclient.xyz/peeringdb 🌐\n\n> A modern, fully-typed TypeScript client for the [PeeringDB API](https://www.peeringdb.com/apidocs/) with automatic retry handling and smart request management.\n\n## Why This Client? ✨\n\n- **🎯 Full TypeScript Support** - Complete type definitions for all PeeringDB resources\n- **🚀 Smart Request Handling** - Automatic retry with exponential backoff for 429 rate limits\n- **🔄 Fluent API** - Clean, chainable methods using `@push.rocks/smartrequest`\n- **📦 Manager Pattern** - Organized access to all PeeringDB resources\n- **🔍 Advanced Querying** - Field filters, pagination, depth control, and field selection\n- **🔐 Auth Optional** - Works with anonymous access or API keys for write operations\n- **✅ Production Ready** - Fully tested with 18/18 tests passing in Node.js\n\n## Installation\n\n```bash\n# Using pnpm (recommended)\npnpm add @apiclient.xyz/peeringdb\n\n# Using npm\nnpm install @apiclient.xyz/peeringdb\n\n# Using yarn\nyarn add @apiclient.xyz/peeringdb\n```\n\n## Quick Start 🚀\n\n```typescript\nimport { PeeringDbClient } from '@apiclient.xyz/peeringdb';\n\n// Create client (anonymous access - perfect for read operations)\nconst client = new PeeringDbClient();\n\n// Fetch networks\nconst networks = await client.networks.list({ limit: 10 });\n\n// Look up a specific network by ASN\nconst google = await client.networks.getByAsn(15169);\nconsole.log(google?.name); // \"Google LLC\"\n\n// Search for facilities\nconst equinixFacilities = await client.facilities.searchByName('Equinix');\n\n// Get exchanges in a specific country\nconst usExchanges = await client.exchanges.getByCountry('US');\n```\n\n## Usage Examples 📚\n\n### Working with Networks\n\n```typescript\n// List networks with pagination\nconst networks = await client.networks.list({\n  limit: 50,\n  skip: 0\n});\n\n// Get a specific network by ASN\nconst cloudflare = await client.networks.getByAsn(13335);\n\n// Search networks by name\nconst results = await client.networks.searchByName('Amazon');\n\n// Get all networks for an organization\nconst orgNetworks = await client.networks.getByOrgId(123);\n\n// Get network with expanded nested objects (depth: 0, 1, or 2)\nconst networkWithDetails = await client.networks.getByAsn(15169, 2);\nconsole.log(networkWithDetails?.org); // Full organization object included\n```\n\n### Working with Organizations\n\n```typescript\n// List organizations\nconst orgs = await client.organizations.list({ limit: 10 });\n\n// Get a specific organization\nconst org = await client.organizations.getById(2);\n\n// Search by name\nconst searchResults = await client.organizations.searchByName('Google');\n\n// Get organizations by country\nconst usOrgs = await client.organizations.getByCountry('US');\n```\n\n### Working with Facilities\n\n```typescript\n// List data center facilities\nconst facilities = await client.facilities.list({ limit: 10 });\n\n// Get a specific facility\nconst facility = await client.facilities.getById(1);\n\n// Search by name\nconst equinix = await client.facilities.searchByName('Equinix');\n\n// Get facilities in a country\nconst usFacilities = await client.facilities.getByCountry('US');\n\n// Get facilities in a specific city\nconst londonDCs = await client.facilities.getByCity('London');\n```\n\n### Working with Internet Exchanges\n\n```typescript\n// List internet exchanges\nconst exchanges = await client.exchanges.list({ limit: 10 });\n\n// Get a specific exchange\nconst exchange = await client.exchanges.getById(1);\n\n// Search by name\nconst amsix = await client.exchanges.searchByName('AMS-IX');\n\n// Get exchanges by country\nconst usIXs = await client.exchanges.getByCountry('US');\n\n// Get exchanges by region\nconst europeIXs = await client.exchanges.getByRegion('Europe');\n```\n\n### Network Connections & Peering Points\n\n```typescript\n// Get network-to-IX connections (where a network peers)\nconst googlePeering = await client.netIxLans.getByAsn(15169);\n\n// Get network-to-facility connections (where a network has presence)\nconst networkPresence = await client.netFacs.getByNetId(123);\n\n// Get all networks present at a facility\nconst facilityNetworks = await client.netFacs.getByFacId(456);\n\n// Get all networks at an exchange\nconst ixNetworks = await client.netIxLans.getByIxLanId(789);\n```\n\n### Convenience Methods 🎁\n\nQuick shortcuts for common operations:\n\n```typescript\n// Quick network lookup by ASN\nconst network = await client.convenience.getNetworkByAsn(15169);\n\n// Search networks (wraps networks.searchByName)\nconst networks = await client.convenience.searchNetworks('Google');\n\n// Search facilities (wraps facilities.searchByName)\nconst facilities = await client.convenience.searchFacilities('Equinix');\n\n// Get all facilities where a network is present\nconst networkFacilities = await client.convenience.getNetworkFacilities(15169);\n\n// Get all exchanges where a network peers\nconst networkExchanges = await client.convenience.getNetworkExchanges(15169);\n```\n\n## Advanced Querying 🔍\n\n### Query Options\n\nAll list and search methods support comprehensive query options:\n\n```typescript\nconst networks = await client.networks.list({\n  limit: 50,                    // Limit number of results\n  skip: 100,                    // Offset for pagination\n  fields: 'id,asn,name',       // Select only specific fields\n  depth: 2,                     // Expand nested objects (0, 1, or 2)\n  since: 1640000000,           // Unix timestamp - get only updates since\n  autoPaginate: false,         // Auto-fetch all pages (default: false)\n\n  // Field filters using PeeringDB's powerful query syntax\n  name__contains: 'Google',\n  asn__in: [15169, 16509, 13335],\n  info_traffic__gte: '100Gbps',\n});\n```\n\n### Field Filter Operators\n\nPeeringDB supports a wide range of filter operators:\n\n```typescript\n// String filters\nname__contains: 'Google'           // Contains substring (case-insensitive)\nname__startswith: 'Google'         // Starts with\nname__in: ['Google', 'Amazon']     // Match any in list\n\n// Number filters\nasn__lt: 20000                     // Less than\nasn__lte: 20000                    // Less than or equal to\nasn__gt: 10000                     // Greater than\nasn__gte: 10000                    // Greater than or equal to\nasn__in: [15169, 16509]           // Match any in list\n\n// Date filters (Unix timestamps)\nupdated__gte: 1640000000          // Updated after timestamp\ncreated__lt: 1650000000           // Created before timestamp\n\n// Boolean filters\ninfo_ipv6: true                   // Exact boolean match\n```\n\n### Depth Parameter\n\nControl how much nested data is expanded in responses:\n\n```typescript\n// depth: 0 - Only IDs for nested objects (default)\nconst network0 = await client.networks.getByAsn(15169, 0);\nconsole.log(network0?.org_id); // Just the ID\n\n// depth: 1 - Basic nested object data\nconst network1 = await client.networks.getByAsn(15169, 1);\nconsole.log(network1?.org?.name); // Organization name included\n\n// depth: 2 - Full nested object expansion\nconst network2 = await client.networks.getByAsn(15169, 2);\nconsole.log(network2?.org?.address); // Full organization details\n```\n\n### Field Selection\n\nRequest only the fields you need to reduce bandwidth:\n\n```typescript\n// Get only specific fields\nconst networks = await client.networks.list({\n  fields: 'id,asn,name,info_type',\n  limit: 100\n});\n\n// Each network object will only contain: id, asn, name, info_type\n```\n\n## Authentication 🔐\n\nFor write operations (create, update, delete), you need a PeeringDB API key:\n\n```typescript\nconst client = new PeeringDbClient('your-api-key-here');\n\n// Create a new organization\nconst newOrg = await client.organizations.create({\n  name: 'My Company',\n  website: 'https://example.com',\n  address1: '123 Main St',\n  city: 'San Francisco',\n  state: 'CA',\n  zipcode: '94102',\n  country: 'US',\n});\n\n// Update an organization\nconst updated = await client.organizations.update(123, {\n  website: 'https://newwebsite.com',\n  notes: 'Updated contact information'\n});\n\n// Delete an organization (careful!)\nawait client.organizations.delete(123);\n```\n\n> **Note:** Most use cases only need read access (anonymous), which doesn't require an API key.\n\n## API Reference 📖\n\n### Client\n\n```typescript\nclass PeeringDbClient {\n  constructor(apiKey?: string)\n\n  // Resource managers\n  organizations: OrganizationManager\n  networks: NetworkManager\n  facilities: FacilityManager\n  exchanges: ExchangeManager\n  netIxLans: NetIxLanManager\n  netFacs: NetFacManager\n  ixLans: IxLanManager\n  ixFacs: IxFacManager\n  ixPfxs: IxPfxManager\n  pocs: PocManager\n\n  // Convenience methods\n  convenience: {\n    getNetworkByAsn(asn: number): Promise<INetwork | null>\n    searchNetworks(name: string): Promise<INetwork[]>\n    searchFacilities(name: string): Promise<IFacility[]>\n    getNetworkFacilities(asn: number): Promise<IFacility[]>\n    getNetworkExchanges(asn: number): Promise<IExchange[]>\n  }\n}\n```\n\n### Manager Methods\n\nAll resource managers provide these standard methods:\n\n```typescript\n// List resources with optional filtering\nlist(options?: IQueryOptions): Promise<T[]>\n\n// Get a single resource by ID\ngetById(id: number, depth?: 0 | 1 | 2): Promise<T | null>\n\n// Create a new resource (requires API key)\ncreate(data: Partial<T>): Promise<T>\n\n// Update an existing resource (requires API key)\nupdate(id: number, data: Partial<T>): Promise<T>\n\n// Delete a resource (requires API key)\ndelete(id: number): Promise<void>\n```\n\nPlus specialized methods for each resource type (e.g., `getByAsn()`, `searchByName()`, `getByCountry()`).\n\n### Available Resource Managers\n\n| Manager | Endpoint | Description |\n|---------|----------|-------------|\n| `organizations` | `/org` | Companies and organizations |\n| `networks` | `/net` | Autonomous systems and networks |\n| `facilities` | `/fac` | Data centers and colocation facilities |\n| `exchanges` | `/ix` | Internet exchange points |\n| `netIxLans` | `/netixlan` | Network-to-exchange connections |\n| `netFacs` | `/netfac` | Network-to-facility connections |\n| `ixLans` | `/ixlan` | Exchange LAN information |\n| `ixFacs` | `/ixfac` | Exchange-to-facility connections |\n| `ixPfxs` | `/ixpfx` | Exchange IP prefixes |\n| `pocs` | `/poc` | Points of contact |\n\n## TypeScript Support 💙\n\nFull TypeScript support with comprehensive interfaces:\n\n```typescript\nimport type {\n  INetwork,\n  IOrganization,\n  IFacility,\n  IExchange,\n  IQueryOptions\n} from '@apiclient.xyz/peeringdb';\n\n// Type-safe queries\nconst options: IQueryOptions = {\n  limit: 50,\n  depth: 2,\n  asn__gte: 10000\n};\n\nconst networks: INetwork[] = await client.networks.list(options);\n\n// Full intellisense for all properties\nnetworks.forEach(network => {\n  console.log(network.asn);          // number\n  console.log(network.name);         // string\n  console.log(network.info_ipv6);    // boolean\n  console.log(network.created);      // string (ISO date)\n});\n```\n\n## Rate Limiting & Retry 🔄\n\nThe client automatically handles PeeringDB's rate limits:\n\n- **Automatic Retry**: Up to 3 retries with exponential backoff\n- **429 Handling**: Smartly backs off when rate limited\n- **Connection Pooling**: Efficient HTTP connection reuse via `@push.rocks/smartrequest`\n\nNo configuration needed - it just works! 🎉\n\n## Error Handling ⚠️\n\n```typescript\ntry {\n  const network = await client.networks.getByAsn(15169);\n  if (!network) {\n    console.log('Network not found');\n  }\n} catch (error) {\n  console.error('API Error:', error.message);\n}\n\n// The client throws errors for:\n// - Network failures\n// - Invalid API responses\n// - PeeringDB API errors (returned in meta.error)\n// - Missing required User-Agent (403 Forbidden)\n```\n\n## Important Notes 📝\n\n### User-Agent Requirement\n\nPeeringDB **requires** a proper User-Agent header or returns `403 Forbidden`. This client automatically sets:\n\n```\nUser-Agent: @apiclient.xyz/peeringdb/1.0.1 (Node.js)\n```\n\nIf you see 403 errors with other HTTP clients, make sure to set a User-Agent!\n\n### Runtime Support\n\n- ✅ **Node.js**: Fully supported and tested (18/18 tests passing)\n- ⚠️ **Bun/Deno**: Limited support due to smartrequest compatibility\n\nThis package is designed primarily for Node.js environments.\n\n## Resources 🔗\n\n- [PeeringDB API Documentation](https://www.peeringdb.com/apidocs/)\n- [PeeringDB Website](https://www.peeringdb.com/)\n- [Source Code Repository](https://code.foss.global/apiclient.xyz/peeringdb)\n- [Issue Tracker](https://code.foss.global/apiclient.xyz/peeringdb/issues)\n\n## Real-World Use Cases 🌍\n\nThis client is perfect for:\n\n- **Network Engineering Tools** - Build automation for peering management\n- **Network Visualization** - Map internet topology and interconnections\n- **Due Diligence** - Research networks and their peering policies\n- **Capacity Planning** - Analyze where networks have presence\n- **Monitoring Systems** - Track changes to network infrastructure\n- **Research Projects** - Study internet topology and peering relationships\n\n## Contributing 🤝\n\nFound a bug? Have a feature request?\n\nPlease open an issue on our [issue tracker](https://code.foss.global/apiclient.xyz/peeringdb/issues).\n\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.\n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH\nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n","readmeFilename":"readme.md","_rev":"1-43885567ce34c257406b36638e9d74a1"}