initial
This commit is contained in:
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
name: Default (not tags)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags-ignore:
|
||||
- '**'
|
||||
|
||||
env:
|
||||
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
|
||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
|
||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install pnpm and npmci
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
|
||||
- name: Run npm prepare
|
||||
run: npmci npm prepare
|
||||
|
||||
- name: Audit production dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --prod
|
||||
continue-on-error: true
|
||||
|
||||
- name: Audit development dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --dev
|
||||
continue-on-error: true
|
||||
|
||||
test:
|
||||
if: ${{ always() }}
|
||||
needs: security
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Test stable
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm test
|
||||
|
||||
- name: Test build
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm build
|
||||
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal file
@@ -0,0 +1,124 @@
|
||||
name: Default (tags)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
|
||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
|
||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Audit production dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --prod
|
||||
continue-on-error: true
|
||||
|
||||
- name: Audit development dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --dev
|
||||
continue-on-error: true
|
||||
|
||||
test:
|
||||
if: ${{ always() }}
|
||||
needs: security
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Test stable
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm test
|
||||
|
||||
- name: Test build
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm build
|
||||
|
||||
release:
|
||||
needs: test
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Release
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm publish
|
||||
|
||||
metadata:
|
||||
needs: test
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Code quality
|
||||
run: |
|
||||
npmci command npm install -g typescript
|
||||
npmci npm install
|
||||
|
||||
- name: Trigger
|
||||
run: npmci trigger
|
||||
|
||||
- name: Build docs and upload artifacts
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
pnpm install -g @git.zone/tsdoc
|
||||
npmci command tsdoc
|
||||
continue-on-error: true
|
||||
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
.nogit/
|
||||
|
||||
# artifacts
|
||||
coverage/
|
||||
public/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
|
||||
# caches
|
||||
.yarn/
|
||||
.cache/
|
||||
.rpt2_cache
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_*/
|
||||
|
||||
# AI
|
||||
.claude/
|
||||
.serena/
|
||||
|
||||
#------# custom
|
||||
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/npmextra.json"],
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"npmci": {
|
||||
"type": "object",
|
||||
"description": "settings for npmci"
|
||||
},
|
||||
"gitzone": {
|
||||
"type": "object",
|
||||
"description": "settings for gitzone",
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
18
npmextra.json
Normal file
18
npmextra.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "apiclient.xyz",
|
||||
"gitrepo": "peeringdb",
|
||||
"description": "an unofficial package for the peeringdb API",
|
||||
"npmPackagename": "@apiclient.xyz/peeringdb",
|
||||
"license": "MIT",
|
||||
"projectDomain": "apiclient.xyz"
|
||||
}
|
||||
},
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
}
|
||||
}
|
||||
51
package.json
Normal file
51
package.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"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": "Task Venture Capital GmbH",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "(tstest test/ --verbose)",
|
||||
"build": "(tsbuild --web --allowimplicitany)",
|
||||
"buildDocs": "(tsdoc)"
|
||||
},
|
||||
"packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34",
|
||||
"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",
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
],
|
||||
"pnpm": {
|
||||
"overrides": {}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
8538
pnpm-lock.yaml
generated
Normal file
8538
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
89
readme.hints.md
Normal file
89
readme.hints.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Implementation Notes
|
||||
|
||||
## Architecture
|
||||
|
||||
This package implements a comprehensive TypeScript client for the PeeringDB API.
|
||||
|
||||
### Key Components
|
||||
|
||||
1. **Client Class** (`PeeringDbClient`)
|
||||
- Main entry point for the API
|
||||
- Uses @push.rocks/smartrequest fluent API
|
||||
- Automatic retry with 429 rate limiting handling
|
||||
- Supports both anonymous and authenticated requests
|
||||
|
||||
2. **Manager Classes** (10 managers)
|
||||
- OrganizationManager - Organizations
|
||||
- NetworkManager - Networks/ASNs
|
||||
- FacilityManager - Colocation facilities
|
||||
- ExchangeManager - Internet Exchanges
|
||||
- NetIxLanManager - Network-IX connections
|
||||
- NetFacManager - Network-facility connections
|
||||
- IxLanManager - IX LAN information
|
||||
- IxFacManager - IX-facility connections
|
||||
- IxPfxManager - IX IP prefixes
|
||||
- PocManager - Points of contact
|
||||
|
||||
3. **Type Definitions**
|
||||
- Comprehensive TypeScript interfaces for all resources
|
||||
- Type-safe query options
|
||||
- Field filter types
|
||||
|
||||
### HTTP Client
|
||||
|
||||
Uses @push.rocks/smartrequest with the fluent API:
|
||||
- `.retry(3)` for automatic retry on failures including 429 rate limits
|
||||
- Chainable methods for building requests
|
||||
- Automatic JSON parsing
|
||||
- **User-Agent header required**: PeeringDB API blocks requests without proper User-Agent
|
||||
- Format: `@apiclient.xyz/peeringdb/1.0.1 (Node.js)`
|
||||
- Without it, API returns 403 Forbidden
|
||||
|
||||
### Response Handling
|
||||
|
||||
PeeringDB API returns responses in this format:
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"status": "ok",
|
||||
"message": "optional"
|
||||
},
|
||||
"data": [...]
|
||||
}
|
||||
```
|
||||
|
||||
The client automatically unwraps the `data` array for convenience.
|
||||
|
||||
### Query Options
|
||||
|
||||
All manager list/search methods support:
|
||||
- `limit` - Pagination limit
|
||||
- `skip` - Offset for pagination
|
||||
- `fields` - Field selection
|
||||
- `depth` - Nested object expansion (0, 1, 2)
|
||||
- `since` - Unix timestamp for recent updates
|
||||
- `autoPaginate` - Auto-fetch all pages
|
||||
- Field filters with operators (`__contains`, `__startswith`, `__in`, `__lt`, `__gte`, etc.)
|
||||
|
||||
### Testing
|
||||
|
||||
Tests use @git.zone/tstest and hit the real PeeringDB API anonymously.
|
||||
To run tests: `pnpm test`
|
||||
|
||||
**Test Results:**
|
||||
- Node.js: All 18 tests pass ✅
|
||||
- Bun/Deno: Limited support due to smartrequest runtime compatibility issues
|
||||
|
||||
The package is fully functional and tested in Node.js, which is the primary target runtime.
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
The smartrequest library automatically handles 429 responses with exponential backoff retry.
|
||||
|
||||
## Development Notes
|
||||
|
||||
- Follow sibling project patterns (DigitalOcean, GitLab, Cloudflare)
|
||||
- Use fluent API for all HTTP requests
|
||||
- Manager classes provide CRUD operations
|
||||
- Convenience methods for common use cases
|
||||
- Logging via @push.rocks/smartlog
|
||||
464
readme.md
Normal file
464
readme.md
Normal file
@@ -0,0 +1,464 @@
|
||||
# @apiclient.xyz/peeringdb 🌐
|
||||
|
||||
> A modern, fully-typed TypeScript client for the [PeeringDB API](https://www.peeringdb.com/apidocs/) with automatic retry handling and smart request management.
|
||||
|
||||
## Why This Client? ✨
|
||||
|
||||
- **🎯 Full TypeScript Support** - Complete type definitions for all PeeringDB resources
|
||||
- **🚀 Smart Request Handling** - Automatic retry with exponential backoff for 429 rate limits
|
||||
- **🔄 Fluent API** - Clean, chainable methods using `@push.rocks/smartrequest`
|
||||
- **📦 Manager Pattern** - Organized access to all PeeringDB resources
|
||||
- **🔍 Advanced Querying** - Field filters, pagination, depth control, and field selection
|
||||
- **🔐 Auth Optional** - Works with anonymous access or API keys for write operations
|
||||
- **✅ Production Ready** - Fully tested with 18/18 tests passing in Node.js
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Using pnpm (recommended)
|
||||
pnpm add @apiclient.xyz/peeringdb
|
||||
|
||||
# Using npm
|
||||
npm install @apiclient.xyz/peeringdb
|
||||
|
||||
# Using yarn
|
||||
yarn add @apiclient.xyz/peeringdb
|
||||
```
|
||||
|
||||
## Quick Start 🚀
|
||||
|
||||
```typescript
|
||||
import { PeeringDbClient } from '@apiclient.xyz/peeringdb';
|
||||
|
||||
// Create client (anonymous access - perfect for read operations)
|
||||
const client = new PeeringDbClient();
|
||||
|
||||
// Fetch networks
|
||||
const networks = await client.networks.list({ limit: 10 });
|
||||
|
||||
// Look up a specific network by ASN
|
||||
const google = await client.networks.getByAsn(15169);
|
||||
console.log(google?.name); // "Google LLC"
|
||||
|
||||
// Search for facilities
|
||||
const equinixFacilities = await client.facilities.searchByName('Equinix');
|
||||
|
||||
// Get exchanges in a specific country
|
||||
const usExchanges = await client.exchanges.getByCountry('US');
|
||||
```
|
||||
|
||||
## Usage Examples 📚
|
||||
|
||||
### Working with Networks
|
||||
|
||||
```typescript
|
||||
// List networks with pagination
|
||||
const networks = await client.networks.list({
|
||||
limit: 50,
|
||||
skip: 0
|
||||
});
|
||||
|
||||
// Get a specific network by ASN
|
||||
const cloudflare = await client.networks.getByAsn(13335);
|
||||
|
||||
// Search networks by name
|
||||
const results = await client.networks.searchByName('Amazon');
|
||||
|
||||
// Get all networks for an organization
|
||||
const orgNetworks = await client.networks.getByOrgId(123);
|
||||
|
||||
// Get network with expanded nested objects (depth: 0, 1, or 2)
|
||||
const networkWithDetails = await client.networks.getByAsn(15169, 2);
|
||||
console.log(networkWithDetails?.org); // Full organization object included
|
||||
```
|
||||
|
||||
### Working with Organizations
|
||||
|
||||
```typescript
|
||||
// List organizations
|
||||
const orgs = await client.organizations.list({ limit: 10 });
|
||||
|
||||
// Get a specific organization
|
||||
const org = await client.organizations.getById(2);
|
||||
|
||||
// Search by name
|
||||
const searchResults = await client.organizations.searchByName('Google');
|
||||
|
||||
// Get organizations by country
|
||||
const usOrgs = await client.organizations.getByCountry('US');
|
||||
```
|
||||
|
||||
### Working with Facilities
|
||||
|
||||
```typescript
|
||||
// List data center facilities
|
||||
const facilities = await client.facilities.list({ limit: 10 });
|
||||
|
||||
// Get a specific facility
|
||||
const facility = await client.facilities.getById(1);
|
||||
|
||||
// Search by name
|
||||
const equinix = await client.facilities.searchByName('Equinix');
|
||||
|
||||
// Get facilities in a country
|
||||
const usFacilities = await client.facilities.getByCountry('US');
|
||||
|
||||
// Get facilities in a specific city
|
||||
const londonDCs = await client.facilities.getByCity('London');
|
||||
```
|
||||
|
||||
### Working with Internet Exchanges
|
||||
|
||||
```typescript
|
||||
// List internet exchanges
|
||||
const exchanges = await client.exchanges.list({ limit: 10 });
|
||||
|
||||
// Get a specific exchange
|
||||
const exchange = await client.exchanges.getById(1);
|
||||
|
||||
// Search by name
|
||||
const amsix = await client.exchanges.searchByName('AMS-IX');
|
||||
|
||||
// Get exchanges by country
|
||||
const usIXs = await client.exchanges.getByCountry('US');
|
||||
|
||||
// Get exchanges by region
|
||||
const europeIXs = await client.exchanges.getByRegion('Europe');
|
||||
```
|
||||
|
||||
### Network Connections & Peering Points
|
||||
|
||||
```typescript
|
||||
// Get network-to-IX connections (where a network peers)
|
||||
const googlePeering = await client.netIxLans.getByAsn(15169);
|
||||
|
||||
// Get network-to-facility connections (where a network has presence)
|
||||
const networkPresence = await client.netFacs.getByNetId(123);
|
||||
|
||||
// Get all networks present at a facility
|
||||
const facilityNetworks = await client.netFacs.getByFacId(456);
|
||||
|
||||
// Get all networks at an exchange
|
||||
const ixNetworks = await client.netIxLans.getByIxLanId(789);
|
||||
```
|
||||
|
||||
### Convenience Methods 🎁
|
||||
|
||||
Quick shortcuts for common operations:
|
||||
|
||||
```typescript
|
||||
// Quick network lookup by ASN
|
||||
const network = await client.convenience.getNetworkByAsn(15169);
|
||||
|
||||
// Search networks (wraps networks.searchByName)
|
||||
const networks = await client.convenience.searchNetworks('Google');
|
||||
|
||||
// Search facilities (wraps facilities.searchByName)
|
||||
const facilities = await client.convenience.searchFacilities('Equinix');
|
||||
|
||||
// Get all facilities where a network is present
|
||||
const networkFacilities = await client.convenience.getNetworkFacilities(15169);
|
||||
|
||||
// Get all exchanges where a network peers
|
||||
const networkExchanges = await client.convenience.getNetworkExchanges(15169);
|
||||
```
|
||||
|
||||
## Advanced Querying 🔍
|
||||
|
||||
### Query Options
|
||||
|
||||
All list and search methods support comprehensive query options:
|
||||
|
||||
```typescript
|
||||
const networks = await client.networks.list({
|
||||
limit: 50, // Limit number of results
|
||||
skip: 100, // Offset for pagination
|
||||
fields: 'id,asn,name', // Select only specific fields
|
||||
depth: 2, // Expand nested objects (0, 1, or 2)
|
||||
since: 1640000000, // Unix timestamp - get only updates since
|
||||
autoPaginate: false, // Auto-fetch all pages (default: false)
|
||||
|
||||
// Field filters using PeeringDB's powerful query syntax
|
||||
name__contains: 'Google',
|
||||
asn__in: [15169, 16509, 13335],
|
||||
info_traffic__gte: '100Gbps',
|
||||
});
|
||||
```
|
||||
|
||||
### Field Filter Operators
|
||||
|
||||
PeeringDB supports a wide range of filter operators:
|
||||
|
||||
```typescript
|
||||
// String filters
|
||||
name__contains: 'Google' // Contains substring (case-insensitive)
|
||||
name__startswith: 'Google' // Starts with
|
||||
name__in: ['Google', 'Amazon'] // Match any in list
|
||||
|
||||
// Number filters
|
||||
asn__lt: 20000 // Less than
|
||||
asn__lte: 20000 // Less than or equal to
|
||||
asn__gt: 10000 // Greater than
|
||||
asn__gte: 10000 // Greater than or equal to
|
||||
asn__in: [15169, 16509] // Match any in list
|
||||
|
||||
// Date filters (Unix timestamps)
|
||||
updated__gte: 1640000000 // Updated after timestamp
|
||||
created__lt: 1650000000 // Created before timestamp
|
||||
|
||||
// Boolean filters
|
||||
info_ipv6: true // Exact boolean match
|
||||
```
|
||||
|
||||
### Depth Parameter
|
||||
|
||||
Control how much nested data is expanded in responses:
|
||||
|
||||
```typescript
|
||||
// depth: 0 - Only IDs for nested objects (default)
|
||||
const network0 = await client.networks.getByAsn(15169, 0);
|
||||
console.log(network0?.org_id); // Just the ID
|
||||
|
||||
// depth: 1 - Basic nested object data
|
||||
const network1 = await client.networks.getByAsn(15169, 1);
|
||||
console.log(network1?.org?.name); // Organization name included
|
||||
|
||||
// depth: 2 - Full nested object expansion
|
||||
const network2 = await client.networks.getByAsn(15169, 2);
|
||||
console.log(network2?.org?.address); // Full organization details
|
||||
```
|
||||
|
||||
### Field Selection
|
||||
|
||||
Request only the fields you need to reduce bandwidth:
|
||||
|
||||
```typescript
|
||||
// Get only specific fields
|
||||
const networks = await client.networks.list({
|
||||
fields: 'id,asn,name,info_type',
|
||||
limit: 100
|
||||
});
|
||||
|
||||
// Each network object will only contain: id, asn, name, info_type
|
||||
```
|
||||
|
||||
## Authentication 🔐
|
||||
|
||||
For write operations (create, update, delete), you need a PeeringDB API key:
|
||||
|
||||
```typescript
|
||||
const client = new PeeringDbClient('your-api-key-here');
|
||||
|
||||
// Create a new organization
|
||||
const newOrg = await client.organizations.create({
|
||||
name: 'My Company',
|
||||
website: 'https://example.com',
|
||||
address1: '123 Main St',
|
||||
city: 'San Francisco',
|
||||
state: 'CA',
|
||||
zipcode: '94102',
|
||||
country: 'US',
|
||||
});
|
||||
|
||||
// Update an organization
|
||||
const updated = await client.organizations.update(123, {
|
||||
website: 'https://newwebsite.com',
|
||||
notes: 'Updated contact information'
|
||||
});
|
||||
|
||||
// Delete an organization (careful!)
|
||||
await client.organizations.delete(123);
|
||||
```
|
||||
|
||||
> **Note:** Most use cases only need read access (anonymous), which doesn't require an API key.
|
||||
|
||||
## API Reference 📖
|
||||
|
||||
### Client
|
||||
|
||||
```typescript
|
||||
class PeeringDbClient {
|
||||
constructor(apiKey?: string)
|
||||
|
||||
// Resource managers
|
||||
organizations: OrganizationManager
|
||||
networks: NetworkManager
|
||||
facilities: FacilityManager
|
||||
exchanges: ExchangeManager
|
||||
netIxLans: NetIxLanManager
|
||||
netFacs: NetFacManager
|
||||
ixLans: IxLanManager
|
||||
ixFacs: IxFacManager
|
||||
ixPfxs: IxPfxManager
|
||||
pocs: PocManager
|
||||
|
||||
// Convenience methods
|
||||
convenience: {
|
||||
getNetworkByAsn(asn: number): Promise<INetwork | null>
|
||||
searchNetworks(name: string): Promise<INetwork[]>
|
||||
searchFacilities(name: string): Promise<IFacility[]>
|
||||
getNetworkFacilities(asn: number): Promise<IFacility[]>
|
||||
getNetworkExchanges(asn: number): Promise<IExchange[]>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Manager Methods
|
||||
|
||||
All resource managers provide these standard methods:
|
||||
|
||||
```typescript
|
||||
// List resources with optional filtering
|
||||
list(options?: IQueryOptions): Promise<T[]>
|
||||
|
||||
// Get a single resource by ID
|
||||
getById(id: number, depth?: 0 | 1 | 2): Promise<T | null>
|
||||
|
||||
// Create a new resource (requires API key)
|
||||
create(data: Partial<T>): Promise<T>
|
||||
|
||||
// Update an existing resource (requires API key)
|
||||
update(id: number, data: Partial<T>): Promise<T>
|
||||
|
||||
// Delete a resource (requires API key)
|
||||
delete(id: number): Promise<void>
|
||||
```
|
||||
|
||||
Plus specialized methods for each resource type (e.g., `getByAsn()`, `searchByName()`, `getByCountry()`).
|
||||
|
||||
### Available Resource Managers
|
||||
|
||||
| Manager | Endpoint | Description |
|
||||
|---------|----------|-------------|
|
||||
| `organizations` | `/org` | Companies and organizations |
|
||||
| `networks` | `/net` | Autonomous systems and networks |
|
||||
| `facilities` | `/fac` | Data centers and colocation facilities |
|
||||
| `exchanges` | `/ix` | Internet exchange points |
|
||||
| `netIxLans` | `/netixlan` | Network-to-exchange connections |
|
||||
| `netFacs` | `/netfac` | Network-to-facility connections |
|
||||
| `ixLans` | `/ixlan` | Exchange LAN information |
|
||||
| `ixFacs` | `/ixfac` | Exchange-to-facility connections |
|
||||
| `ixPfxs` | `/ixpfx` | Exchange IP prefixes |
|
||||
| `pocs` | `/poc` | Points of contact |
|
||||
|
||||
## TypeScript Support 💙
|
||||
|
||||
Full TypeScript support with comprehensive interfaces:
|
||||
|
||||
```typescript
|
||||
import type {
|
||||
INetwork,
|
||||
IOrganization,
|
||||
IFacility,
|
||||
IExchange,
|
||||
IQueryOptions
|
||||
} from '@apiclient.xyz/peeringdb';
|
||||
|
||||
// Type-safe queries
|
||||
const options: IQueryOptions = {
|
||||
limit: 50,
|
||||
depth: 2,
|
||||
asn__gte: 10000
|
||||
};
|
||||
|
||||
const networks: INetwork[] = await client.networks.list(options);
|
||||
|
||||
// Full intellisense for all properties
|
||||
networks.forEach(network => {
|
||||
console.log(network.asn); // number
|
||||
console.log(network.name); // string
|
||||
console.log(network.info_ipv6); // boolean
|
||||
console.log(network.created); // string (ISO date)
|
||||
});
|
||||
```
|
||||
|
||||
## Rate Limiting & Retry 🔄
|
||||
|
||||
The client automatically handles PeeringDB's rate limits:
|
||||
|
||||
- **Automatic Retry**: Up to 3 retries with exponential backoff
|
||||
- **429 Handling**: Smartly backs off when rate limited
|
||||
- **Connection Pooling**: Efficient HTTP connection reuse via `@push.rocks/smartrequest`
|
||||
|
||||
No configuration needed - it just works! 🎉
|
||||
|
||||
## Error Handling ⚠️
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const network = await client.networks.getByAsn(15169);
|
||||
if (!network) {
|
||||
console.log('Network not found');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('API Error:', error.message);
|
||||
}
|
||||
|
||||
// The client throws errors for:
|
||||
// - Network failures
|
||||
// - Invalid API responses
|
||||
// - PeeringDB API errors (returned in meta.error)
|
||||
// - Missing required User-Agent (403 Forbidden)
|
||||
```
|
||||
|
||||
## Important Notes 📝
|
||||
|
||||
### User-Agent Requirement
|
||||
|
||||
PeeringDB **requires** a proper User-Agent header or returns `403 Forbidden`. This client automatically sets:
|
||||
|
||||
```
|
||||
User-Agent: @apiclient.xyz/peeringdb/1.0.1 (Node.js)
|
||||
```
|
||||
|
||||
If you see 403 errors with other HTTP clients, make sure to set a User-Agent!
|
||||
|
||||
### Runtime Support
|
||||
|
||||
- ✅ **Node.js**: Fully supported and tested (18/18 tests passing)
|
||||
- ⚠️ **Bun/Deno**: Limited support due to smartrequest compatibility
|
||||
|
||||
This package is designed primarily for Node.js environments.
|
||||
|
||||
## Resources 🔗
|
||||
|
||||
- [PeeringDB API Documentation](https://www.peeringdb.com/apidocs/)
|
||||
- [PeeringDB Website](https://www.peeringdb.com/)
|
||||
- [Source Code Repository](https://code.foss.global/apiclient.xyz/peeringdb)
|
||||
- [Issue Tracker](https://code.foss.global/apiclient.xyz/peeringdb/issues)
|
||||
|
||||
## Real-World Use Cases 🌍
|
||||
|
||||
This client is perfect for:
|
||||
|
||||
- **Network Engineering Tools** - Build automation for peering management
|
||||
- **Network Visualization** - Map internet topology and interconnections
|
||||
- **Due Diligence** - Research networks and their peering policies
|
||||
- **Capacity Planning** - Analyze where networks have presence
|
||||
- **Monitoring Systems** - Track changes to network infrastructure
|
||||
- **Research Projects** - Study internet topology and peering relationships
|
||||
|
||||
## Contributing 🤝
|
||||
|
||||
Found a bug? Have a feature request?
|
||||
|
||||
Please open an issue on our [issue tracker](https://code.foss.global/apiclient.xyz/peeringdb/issues).
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This 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.
|
||||
|
||||
**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.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This 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.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By 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.
|
||||
153
test/test.node+bun+deno.ts
Normal file
153
test/test.node+bun+deno.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import { PeeringDbClient } from '../ts/index.js';
|
||||
|
||||
let client: PeeringDbClient;
|
||||
|
||||
// Initialize client
|
||||
tap.test('should create a PeeringDB client instance', async () => {
|
||||
client = new PeeringDbClient();
|
||||
expect(client).toBeInstanceOf(PeeringDbClient);
|
||||
expect(client.networks).toBeDefined();
|
||||
expect(client.organizations).toBeDefined();
|
||||
expect(client.facilities).toBeDefined();
|
||||
expect(client.exchanges).toBeDefined();
|
||||
});
|
||||
|
||||
// Test network queries
|
||||
tap.test('should fetch networks list', async () => {
|
||||
const networks = await client.networks.list({ limit: 5 });
|
||||
expect(Array.isArray(networks)).toEqual(true);
|
||||
expect(networks.length).toBeGreaterThan(0);
|
||||
expect(networks.length).toBeLessThanOrEqual(5);
|
||||
expect(networks[0]).toHaveProperty('id');
|
||||
expect(networks[0]).toHaveProperty('asn');
|
||||
expect(networks[0]).toHaveProperty('name');
|
||||
});
|
||||
|
||||
tap.test('should fetch a network by ASN', async () => {
|
||||
// Google's ASN
|
||||
const network = await client.networks.getByAsn(15169);
|
||||
expect(network).toBeDefined();
|
||||
expect(network?.asn).toEqual(15169);
|
||||
expect(network?.name).toBeDefined();
|
||||
});
|
||||
|
||||
tap.test('should search networks by name', async () => {
|
||||
const networks = await client.networks.searchByName('Google', { limit: 5 });
|
||||
expect(Array.isArray(networks)).toEqual(true);
|
||||
expect(networks.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
// Test organization queries
|
||||
tap.test('should fetch organizations list', async () => {
|
||||
const orgs = await client.organizations.list({ limit: 5 });
|
||||
expect(Array.isArray(orgs)).toEqual(true);
|
||||
expect(orgs.length).toBeGreaterThan(0);
|
||||
expect(orgs[0]).toHaveProperty('id');
|
||||
expect(orgs[0]).toHaveProperty('name');
|
||||
});
|
||||
|
||||
tap.test('should fetch organization by ID', async () => {
|
||||
const org = await client.organizations.getById(2);
|
||||
expect(org).toBeDefined();
|
||||
expect(org?.id).toEqual(2);
|
||||
expect(org?.name).toBeDefined();
|
||||
});
|
||||
|
||||
// Test facility queries
|
||||
tap.test('should fetch facilities list', async () => {
|
||||
const facilities = await client.facilities.list({ limit: 5 });
|
||||
expect(Array.isArray(facilities)).toEqual(true);
|
||||
expect(facilities.length).toBeGreaterThan(0);
|
||||
expect(facilities[0]).toHaveProperty('id');
|
||||
expect(facilities[0]).toHaveProperty('name');
|
||||
expect(facilities[0]).toHaveProperty('city');
|
||||
});
|
||||
|
||||
tap.test('should search facilities by name', async () => {
|
||||
const facilities = await client.facilities.searchByName('Equinix', { limit: 5 });
|
||||
expect(Array.isArray(facilities)).toEqual(true);
|
||||
expect(facilities.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
tap.test('should get facilities by country', async () => {
|
||||
const facilities = await client.facilities.getByCountry('US', { limit: 5 });
|
||||
expect(Array.isArray(facilities)).toEqual(true);
|
||||
expect(facilities.length).toBeGreaterThan(0);
|
||||
expect(facilities[0].country).toEqual('US');
|
||||
});
|
||||
|
||||
// Test exchange queries
|
||||
tap.test('should fetch exchanges list', async () => {
|
||||
const exchanges = await client.exchanges.list({ limit: 5 });
|
||||
expect(Array.isArray(exchanges)).toEqual(true);
|
||||
expect(exchanges.length).toBeGreaterThan(0);
|
||||
expect(exchanges[0]).toHaveProperty('id');
|
||||
expect(exchanges[0]).toHaveProperty('name');
|
||||
});
|
||||
|
||||
tap.test('should search exchanges by name', async () => {
|
||||
const exchanges = await client.exchanges.searchByName('AMS-IX', { limit: 5 });
|
||||
expect(Array.isArray(exchanges)).toEqual(true);
|
||||
expect(exchanges.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
// Test query parameters
|
||||
tap.test('should support field selection', async () => {
|
||||
const networks = await client.networks.list({
|
||||
limit: 1,
|
||||
fields: 'id,asn,name',
|
||||
});
|
||||
expect(networks.length).toEqual(1);
|
||||
expect(networks[0]).toHaveProperty('id');
|
||||
expect(networks[0]).toHaveProperty('asn');
|
||||
expect(networks[0]).toHaveProperty('name');
|
||||
});
|
||||
|
||||
tap.test('should support depth parameter', async () => {
|
||||
const network = await client.networks.getByAsn(15169, 2);
|
||||
expect(network).toBeDefined();
|
||||
expect(network?.asn).toEqual(15169);
|
||||
// With depth=2, org should be expanded to full object
|
||||
if (network?.org) {
|
||||
expect(typeof network.org).toEqual('object');
|
||||
}
|
||||
});
|
||||
|
||||
// Test derived objects
|
||||
tap.test('should fetch network-IX connections', async () => {
|
||||
const netixlans = await client.netIxLans.list({ limit: 5 });
|
||||
expect(Array.isArray(netixlans)).toEqual(true);
|
||||
expect(netixlans.length).toBeGreaterThan(0);
|
||||
expect(netixlans[0]).toHaveProperty('net_id');
|
||||
expect(netixlans[0]).toHaveProperty('ixlan_id');
|
||||
});
|
||||
|
||||
tap.test('should fetch network-facility connections', async () => {
|
||||
const netfacs = await client.netFacs.list({ limit: 5 });
|
||||
expect(Array.isArray(netfacs)).toEqual(true);
|
||||
expect(netfacs.length).toBeGreaterThan(0);
|
||||
expect(netfacs[0]).toHaveProperty('net_id');
|
||||
expect(netfacs[0]).toHaveProperty('fac_id');
|
||||
});
|
||||
|
||||
// Test convenience methods
|
||||
tap.test('convenience: should get network by ASN', async () => {
|
||||
const network = await client.convenience.getNetworkByAsn(15169);
|
||||
expect(network).toBeDefined();
|
||||
expect(network?.asn).toEqual(15169);
|
||||
});
|
||||
|
||||
tap.test('convenience: should search networks', async () => {
|
||||
const networks = await client.convenience.searchNetworks('Google');
|
||||
expect(Array.isArray(networks)).toEqual(true);
|
||||
expect(networks.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
tap.test('convenience: should search facilities', async () => {
|
||||
const facilities = await client.convenience.searchFacilities('Equinix');
|
||||
expect(Array.isArray(facilities)).toEqual(true);
|
||||
expect(facilities.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
25
ts/index.ts
Normal file
25
ts/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @apiclient.xyz/peeringdb
|
||||
* PeeringDB API Client for Node.js
|
||||
*/
|
||||
|
||||
// Export main client
|
||||
export { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
|
||||
// Export all manager classes
|
||||
export { OrganizationManager } from './peeringdb.classes.organizationmanager.js';
|
||||
export { NetworkManager } from './peeringdb.classes.networkmanager.js';
|
||||
export { FacilityManager } from './peeringdb.classes.facilitymanager.js';
|
||||
export { ExchangeManager } from './peeringdb.classes.exchangemanager.js';
|
||||
export { NetIxLanManager } from './peeringdb.classes.netixlanmanager.js';
|
||||
export { NetFacManager } from './peeringdb.classes.netfacmanager.js';
|
||||
export { IxLanManager } from './peeringdb.classes.ixlanmanager.js';
|
||||
export { IxFacManager } from './peeringdb.classes.ixfacmanager.js';
|
||||
export { IxPfxManager } from './peeringdb.classes.ixpfxmanager.js';
|
||||
export { PocManager } from './peeringdb.classes.pocmanager.js';
|
||||
|
||||
// Export types
|
||||
export * from './peeringdb.types.js';
|
||||
|
||||
// Export interfaces
|
||||
export * from './interfaces/index.js';
|
||||
15
ts/interfaces/index.ts
Normal file
15
ts/interfaces/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* PeeringDB API Interfaces
|
||||
* Export all interface definitions for PeeringDB API resources
|
||||
*/
|
||||
|
||||
export * from './peeringdb.api.organization.js';
|
||||
export * from './peeringdb.api.network.js';
|
||||
export * from './peeringdb.api.facility.js';
|
||||
export * from './peeringdb.api.exchange.js';
|
||||
export * from './peeringdb.api.netixlan.js';
|
||||
export * from './peeringdb.api.netfac.js';
|
||||
export * from './peeringdb.api.ixlan.js';
|
||||
export * from './peeringdb.api.ixfac.js';
|
||||
export * from './peeringdb.api.ixpfx.js';
|
||||
export * from './peeringdb.api.poc.js';
|
||||
79
ts/interfaces/peeringdb.api.exchange.ts
Normal file
79
ts/interfaces/peeringdb.api.exchange.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Internet Exchange object from PeeringDB API
|
||||
* Represents an Internet Exchange Point (IXP)
|
||||
*/
|
||||
export interface IExchange extends IPeeringDbBaseObject {
|
||||
/** Exchange ID */
|
||||
id: number;
|
||||
|
||||
/** Organization ID */
|
||||
org_id: number;
|
||||
|
||||
/** Organization object (when depth > 0) */
|
||||
org?: any;
|
||||
|
||||
/** Exchange name */
|
||||
name: string;
|
||||
|
||||
/** Also known as (alternate names) */
|
||||
aka: string;
|
||||
|
||||
/** Name long */
|
||||
name_long: string;
|
||||
|
||||
/** Website */
|
||||
website: string;
|
||||
|
||||
/** City */
|
||||
city: string;
|
||||
|
||||
/** Country code (ISO 3166-1 alpha-2) */
|
||||
country: string;
|
||||
|
||||
/** Region/continent */
|
||||
region_continent: string;
|
||||
|
||||
/** Media type (Ethernet, ATM, etc.) */
|
||||
media: string;
|
||||
|
||||
/** Notes (markdown) */
|
||||
notes: string;
|
||||
|
||||
/** Proto unicast */
|
||||
proto_unicast: boolean;
|
||||
|
||||
/** Proto multicast */
|
||||
proto_multicast: boolean;
|
||||
|
||||
/** Proto IPv6 */
|
||||
proto_ipv6: boolean;
|
||||
|
||||
/** URL stats */
|
||||
url_stats: string;
|
||||
|
||||
/** Tech email */
|
||||
tech_email: string;
|
||||
|
||||
/** Tech phone */
|
||||
tech_phone: string;
|
||||
|
||||
/** Policy email */
|
||||
policy_email: string;
|
||||
|
||||
/** Policy phone */
|
||||
policy_phone: string;
|
||||
|
||||
/** Sales email */
|
||||
sales_email: string;
|
||||
|
||||
/** Sales phone */
|
||||
sales_phone: string;
|
||||
|
||||
/** Related IX LANs */
|
||||
ixlan_set?: number[] | any[];
|
||||
|
||||
/** Related IX-facility connections */
|
||||
ixfac_set?: number[] | any[];
|
||||
}
|
||||
88
ts/interfaces/peeringdb.api.facility.ts
Normal file
88
ts/interfaces/peeringdb.api.facility.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Facility object from PeeringDB API
|
||||
* Represents a colocation facility or data center
|
||||
*/
|
||||
export interface IFacility extends IPeeringDbBaseObject {
|
||||
/** Facility ID */
|
||||
id: number;
|
||||
|
||||
/** Organization ID */
|
||||
org_id: number;
|
||||
|
||||
/** Organization object (when depth > 0) */
|
||||
org?: any;
|
||||
|
||||
/** Facility name */
|
||||
name: string;
|
||||
|
||||
/** Also known as (alternate names) */
|
||||
aka: string;
|
||||
|
||||
/** Website */
|
||||
website: string;
|
||||
|
||||
/** CLLI code */
|
||||
clli: string;
|
||||
|
||||
/** Renater code */
|
||||
renater: string;
|
||||
|
||||
/** NPL code */
|
||||
npanxx: string;
|
||||
|
||||
/** Notes (markdown) */
|
||||
notes: string;
|
||||
|
||||
/** Address line 1 */
|
||||
address1: string;
|
||||
|
||||
/** Address line 2 */
|
||||
address2: string;
|
||||
|
||||
/** City */
|
||||
city: string;
|
||||
|
||||
/** State/Province */
|
||||
state: string;
|
||||
|
||||
/** Zip/Postal code */
|
||||
zipcode: string;
|
||||
|
||||
/** Country code (ISO 3166-1 alpha-2) */
|
||||
country: string;
|
||||
|
||||
/** Latitude */
|
||||
latitude: number | null;
|
||||
|
||||
/** Longitude */
|
||||
longitude: number | null;
|
||||
|
||||
/** Floor area (sqm) */
|
||||
floor_area: number | null;
|
||||
|
||||
/** Available voltage services */
|
||||
available_voltage_services: string;
|
||||
|
||||
/** Power redundancy */
|
||||
power_redundancy: string;
|
||||
|
||||
/** Diverse serving substations */
|
||||
diverse_serving_substations: boolean;
|
||||
|
||||
/** Property */
|
||||
property: string;
|
||||
|
||||
/** Campus ID */
|
||||
campus_id: number | null;
|
||||
|
||||
/** Campus object (when depth > 0) */
|
||||
campus?: any;
|
||||
|
||||
/** Related network-facility connections */
|
||||
netfac_set?: number[] | any[];
|
||||
|
||||
/** Related IX-facility connections */
|
||||
ixfac_set?: number[] | any[];
|
||||
}
|
||||
22
ts/interfaces/peeringdb.api.ixfac.ts
Normal file
22
ts/interfaces/peeringdb.api.ixfac.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* IX Facility object from PeeringDB API
|
||||
* Represents the connection between an Internet Exchange and a facility
|
||||
*/
|
||||
export interface IIxFac extends IPeeringDbBaseObject {
|
||||
/** IxFac ID */
|
||||
id: number;
|
||||
|
||||
/** Exchange ID */
|
||||
ix_id: number;
|
||||
|
||||
/** Exchange object (when depth > 0) */
|
||||
ix?: any;
|
||||
|
||||
/** Facility ID */
|
||||
fac_id: number;
|
||||
|
||||
/** Facility object (when depth > 0) */
|
||||
fac?: any;
|
||||
}
|
||||
43
ts/interfaces/peeringdb.api.ixlan.ts
Normal file
43
ts/interfaces/peeringdb.api.ixlan.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* IX LAN object from PeeringDB API
|
||||
* Represents a LAN at an Internet Exchange
|
||||
*/
|
||||
export interface IIxLan extends IPeeringDbBaseObject {
|
||||
/** IxLan ID */
|
||||
id: number;
|
||||
|
||||
/** Exchange ID */
|
||||
ix_id: number;
|
||||
|
||||
/** Exchange object (when depth > 0) */
|
||||
ix?: any;
|
||||
|
||||
/** LAN name */
|
||||
name: string;
|
||||
|
||||
/** Description */
|
||||
descr: string;
|
||||
|
||||
/** MTU size */
|
||||
mtu: number;
|
||||
|
||||
/** VLANs */
|
||||
vlan: number | null;
|
||||
|
||||
/** Dot1q support */
|
||||
dot1q_support: boolean;
|
||||
|
||||
/** Route server ASN */
|
||||
rs_asn: number | null;
|
||||
|
||||
/** ARP sponge */
|
||||
arp_sponge: string | null;
|
||||
|
||||
/** Related IX prefixes */
|
||||
ixpfx_set?: number[] | any[];
|
||||
|
||||
/** Related network IX LANs */
|
||||
netixlan_set?: number[] | any[];
|
||||
}
|
||||
25
ts/interfaces/peeringdb.api.ixpfx.ts
Normal file
25
ts/interfaces/peeringdb.api.ixpfx.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* IX Prefix object from PeeringDB API
|
||||
* Represents an IP prefix used by an Internet Exchange
|
||||
*/
|
||||
export interface IIxPfx extends IPeeringDbBaseObject {
|
||||
/** IxPfx ID */
|
||||
id: number;
|
||||
|
||||
/** IX LAN ID */
|
||||
ixlan_id: number;
|
||||
|
||||
/** IX LAN object (when depth > 0) */
|
||||
ixlan?: any;
|
||||
|
||||
/** IP prefix */
|
||||
prefix: string;
|
||||
|
||||
/** Protocol (IPv4 or IPv6) */
|
||||
protocol: string;
|
||||
|
||||
/** Peering point */
|
||||
in_dfz: boolean;
|
||||
}
|
||||
34
ts/interfaces/peeringdb.api.netfac.ts
Normal file
34
ts/interfaces/peeringdb.api.netfac.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Network Facility object from PeeringDB API
|
||||
* Represents a network's presence at a colocation facility
|
||||
*/
|
||||
export interface INetFac extends IPeeringDbBaseObject {
|
||||
/** NetFac ID */
|
||||
id: number;
|
||||
|
||||
/** Network ID */
|
||||
net_id: number;
|
||||
|
||||
/** Network object (when depth > 0) */
|
||||
net?: any;
|
||||
|
||||
/** Facility ID */
|
||||
fac_id: number;
|
||||
|
||||
/** Facility object (when depth > 0) */
|
||||
fac?: any;
|
||||
|
||||
/** Availability percentage */
|
||||
avail_sonet: boolean;
|
||||
|
||||
/** Availability percentage */
|
||||
avail_ethernet: boolean;
|
||||
|
||||
/** Availability percentage */
|
||||
avail_atm: boolean;
|
||||
|
||||
/** Local ASN */
|
||||
local_asn: number | null;
|
||||
}
|
||||
43
ts/interfaces/peeringdb.api.netixlan.ts
Normal file
43
ts/interfaces/peeringdb.api.netixlan.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Network IX LAN object from PeeringDB API
|
||||
* Represents a network's presence at an Internet Exchange
|
||||
*/
|
||||
export interface INetIxLan extends IPeeringDbBaseObject {
|
||||
/** NetIxLan ID */
|
||||
id: number;
|
||||
|
||||
/** Network ID */
|
||||
net_id: number;
|
||||
|
||||
/** Network object (when depth > 0) */
|
||||
net?: any;
|
||||
|
||||
/** IX LAN ID */
|
||||
ixlan_id: number;
|
||||
|
||||
/** IX LAN object (when depth > 0) */
|
||||
ixlan?: any;
|
||||
|
||||
/** Notes (markdown) */
|
||||
notes: string;
|
||||
|
||||
/** Speed in Mbps */
|
||||
speed: number;
|
||||
|
||||
/** Autonomous System Number (ASN) */
|
||||
asn: number;
|
||||
|
||||
/** IPv4 address */
|
||||
ipaddr4: string | null;
|
||||
|
||||
/** IPv6 address */
|
||||
ipaddr6: string | null;
|
||||
|
||||
/** Is route server */
|
||||
is_rs_peer: boolean;
|
||||
|
||||
/** Operational status */
|
||||
operational: boolean;
|
||||
}
|
||||
91
ts/interfaces/peeringdb.api.network.ts
Normal file
91
ts/interfaces/peeringdb.api.network.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Network object from PeeringDB API
|
||||
* Represents an autonomous system (AS) and its peering information
|
||||
*/
|
||||
export interface INetwork extends IPeeringDbBaseObject {
|
||||
/** Network ID */
|
||||
id: number;
|
||||
|
||||
/** Organization ID */
|
||||
org_id: number;
|
||||
|
||||
/** Organization object (when depth > 0) */
|
||||
org?: any;
|
||||
|
||||
/** Network name */
|
||||
name: string;
|
||||
|
||||
/** Also known as (alternate names) */
|
||||
aka: string;
|
||||
|
||||
/** Website */
|
||||
website: string;
|
||||
|
||||
/** Autonomous System Number (ASN) */
|
||||
asn: number;
|
||||
|
||||
/** Looking glass URL */
|
||||
looking_glass: string;
|
||||
|
||||
/** Route server URL */
|
||||
route_server: string;
|
||||
|
||||
/** IRR as-set/route-set */
|
||||
irr_as_set: string;
|
||||
|
||||
/** Network information (markdown) */
|
||||
info_type: string;
|
||||
|
||||
/** Network traffic levels */
|
||||
info_traffic: string;
|
||||
|
||||
/** Network ratios */
|
||||
info_ratio: string;
|
||||
|
||||
/** Network scope */
|
||||
info_scope: string;
|
||||
|
||||
/** Network types (NSP, Content, etc.) */
|
||||
info_types: string;
|
||||
|
||||
/** Peering policy */
|
||||
policy_url: string;
|
||||
|
||||
/** General policy (Open, Selective, etc.) */
|
||||
policy_general: string;
|
||||
|
||||
/** Location requirements for peering */
|
||||
policy_locations: string;
|
||||
|
||||
/** Ratio requirement */
|
||||
policy_ratio: boolean;
|
||||
|
||||
/** Contract requirement */
|
||||
policy_contracts: string;
|
||||
|
||||
/** Notes (markdown) */
|
||||
notes: string;
|
||||
|
||||
/** Number of unicast IPv4 prefixes */
|
||||
info_unicast: boolean;
|
||||
|
||||
/** Number of unicast IPv6 prefixes */
|
||||
info_ipv6: boolean;
|
||||
|
||||
/** Number of multicast prefixes */
|
||||
info_multicast: boolean;
|
||||
|
||||
/** Is never via route servers */
|
||||
info_never_via_route_servers: boolean;
|
||||
|
||||
/** Related network contacts */
|
||||
poc_set?: number[] | any[];
|
||||
|
||||
/** Related network-facility connections */
|
||||
netfac_set?: number[] | any[];
|
||||
|
||||
/** Related network-IX connections */
|
||||
netixlan_set?: number[] | any[];
|
||||
}
|
||||
55
ts/interfaces/peeringdb.api.organization.ts
Normal file
55
ts/interfaces/peeringdb.api.organization.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Organization object from PeeringDB API
|
||||
* Organizations are the root object in PeeringDB and represent companies or entities
|
||||
*/
|
||||
export interface IOrganization extends IPeeringDbBaseObject {
|
||||
/** Organization ID */
|
||||
id: number;
|
||||
|
||||
/** Organization name */
|
||||
name: string;
|
||||
|
||||
/** Organization website */
|
||||
website: string;
|
||||
|
||||
/** Organization notes (markdown) */
|
||||
notes: string;
|
||||
|
||||
/** Address line 1 */
|
||||
address1: string;
|
||||
|
||||
/** Address line 2 */
|
||||
address2: string;
|
||||
|
||||
/** City */
|
||||
city: string;
|
||||
|
||||
/** State/Province */
|
||||
state: string;
|
||||
|
||||
/** Zip/Postal code */
|
||||
zipcode: string;
|
||||
|
||||
/** Country code (ISO 3166-1 alpha-2) */
|
||||
country: string;
|
||||
|
||||
/** Latitude */
|
||||
latitude: number | null;
|
||||
|
||||
/** Longitude */
|
||||
longitude: number | null;
|
||||
|
||||
/** Floor area (sqm) */
|
||||
floor_area: number | null;
|
||||
|
||||
/** Related networks */
|
||||
net_set?: number[] | any[];
|
||||
|
||||
/** Related facilities */
|
||||
fac_set?: number[] | any[];
|
||||
|
||||
/** Related internet exchanges */
|
||||
ix_set?: number[] | any[];
|
||||
}
|
||||
34
ts/interfaces/peeringdb.api.poc.ts
Normal file
34
ts/interfaces/peeringdb.api.poc.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { IPeeringDbBaseObject } from '../peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Point of Contact object from PeeringDB API
|
||||
* Represents a contact person for a network
|
||||
*/
|
||||
export interface IPointOfContact extends IPeeringDbBaseObject {
|
||||
/** POC ID */
|
||||
id: number;
|
||||
|
||||
/** Network ID */
|
||||
net_id: number;
|
||||
|
||||
/** Network object (when depth > 0) */
|
||||
net?: any;
|
||||
|
||||
/** Role/Position */
|
||||
role: string;
|
||||
|
||||
/** Visible (public/private/users) */
|
||||
visible: string;
|
||||
|
||||
/** Contact name */
|
||||
name: string;
|
||||
|
||||
/** Phone number */
|
||||
phone: string;
|
||||
|
||||
/** Email address */
|
||||
email: string;
|
||||
|
||||
/** URL */
|
||||
url: string;
|
||||
}
|
||||
296
ts/peeringdb.classes.client.ts
Normal file
296
ts/peeringdb.classes.client.ts
Normal file
@@ -0,0 +1,296 @@
|
||||
import { smartlog, smartrequest } from './plugins.js';
|
||||
import {
|
||||
type IPeeringDbResponse,
|
||||
type THttpMethod,
|
||||
type IQueryOptions,
|
||||
} from './peeringdb.types.js';
|
||||
|
||||
// Import manager classes (will be created next)
|
||||
import { OrganizationManager } from './peeringdb.classes.organizationmanager.js';
|
||||
import { NetworkManager } from './peeringdb.classes.networkmanager.js';
|
||||
import { FacilityManager } from './peeringdb.classes.facilitymanager.js';
|
||||
import { ExchangeManager } from './peeringdb.classes.exchangemanager.js';
|
||||
import { NetIxLanManager } from './peeringdb.classes.netixlanmanager.js';
|
||||
import { NetFacManager } from './peeringdb.classes.netfacmanager.js';
|
||||
import { IxLanManager } from './peeringdb.classes.ixlanmanager.js';
|
||||
import { IxFacManager } from './peeringdb.classes.ixfacmanager.js';
|
||||
import { IxPfxManager } from './peeringdb.classes.ixpfxmanager.js';
|
||||
import { PocManager } from './peeringdb.classes.pocmanager.js';
|
||||
|
||||
/**
|
||||
* PeeringDB API Client
|
||||
* Provides access to the PeeringDB API using native fetch
|
||||
*/
|
||||
export class PeeringDbClient {
|
||||
private apiKey: string | null = null;
|
||||
private baseUrl: string = 'https://www.peeringdb.com/api';
|
||||
private logger: smartlog.Smartlog;
|
||||
|
||||
// Manager instances
|
||||
public organizations: OrganizationManager;
|
||||
public networks: NetworkManager;
|
||||
public facilities: FacilityManager;
|
||||
public exchanges: ExchangeManager;
|
||||
public netIxLans: NetIxLanManager;
|
||||
public netFacs: NetFacManager;
|
||||
public ixLans: IxLanManager;
|
||||
public ixFacs: IxFacManager;
|
||||
public ixPfxs: IxPfxManager;
|
||||
public pocs: PocManager;
|
||||
|
||||
/**
|
||||
* Create a new PeeringDB API client
|
||||
* @param apiKey Optional API key for authenticated requests
|
||||
*/
|
||||
constructor(apiKey?: string) {
|
||||
this.apiKey = apiKey || null;
|
||||
this.logger = new smartlog.Smartlog({
|
||||
logContext: {
|
||||
company: 'Task Venture Capital',
|
||||
companyunit: '@apiclient.xyz/peeringdb',
|
||||
containerName: 'PeeringDbClient',
|
||||
},
|
||||
});
|
||||
|
||||
// Initialize managers
|
||||
this.organizations = new OrganizationManager(this);
|
||||
this.networks = new NetworkManager(this);
|
||||
this.facilities = new FacilityManager(this);
|
||||
this.exchanges = new ExchangeManager(this);
|
||||
this.netIxLans = new NetIxLanManager(this);
|
||||
this.netFacs = new NetFacManager(this);
|
||||
this.ixLans = new IxLanManager(this);
|
||||
this.ixFacs = new IxFacManager(this);
|
||||
this.ixPfxs = new IxPfxManager(this);
|
||||
this.pocs = new PocManager(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request to the PeeringDB API
|
||||
* @param endpoint API endpoint (e.g., 'net', 'org', 'fac')
|
||||
* @param method HTTP method
|
||||
* @param options Query options and parameters
|
||||
* @param body Request body for POST/PUT/PATCH
|
||||
* @returns Array of results (unwrapped from meta wrapper)
|
||||
*/
|
||||
public async request<T = any>(
|
||||
endpoint: string,
|
||||
method: THttpMethod = 'GET',
|
||||
options: IQueryOptions = {},
|
||||
body?: any
|
||||
): Promise<T[]> {
|
||||
const url = this.buildUrl(endpoint, options);
|
||||
|
||||
this.logger.log('info', `${method} ${url}`);
|
||||
|
||||
// Build request using fluent API
|
||||
let requestClient = smartrequest.SmartRequestClient.create()
|
||||
.url(url)
|
||||
.header('Accept', 'application/json')
|
||||
.header('User-Agent', '@apiclient.xyz/peeringdb/1.0.1 (Node.js)')
|
||||
.retry(3); // Retry up to 3 times (handles 429)
|
||||
|
||||
// Add API key if available
|
||||
if (this.apiKey) {
|
||||
requestClient = requestClient.header('Authorization', `Api-Key ${this.apiKey}`);
|
||||
}
|
||||
|
||||
// Add body for POST/PUT/PATCH requests
|
||||
if (body && ['POST', 'PUT', 'PATCH'].includes(method)) {
|
||||
requestClient = requestClient.json(body);
|
||||
}
|
||||
|
||||
try {
|
||||
// Execute the appropriate HTTP method
|
||||
let response;
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
response = await requestClient.get();
|
||||
break;
|
||||
case 'POST':
|
||||
response = await requestClient.post();
|
||||
break;
|
||||
case 'PUT':
|
||||
response = await requestClient.put();
|
||||
break;
|
||||
case 'DELETE':
|
||||
response = await requestClient.delete();
|
||||
break;
|
||||
case 'PATCH':
|
||||
response = await requestClient.patch();
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported HTTP method: ${method}`);
|
||||
}
|
||||
|
||||
// Response body is automatically parsed as JSON by smartrequest
|
||||
const data: IPeeringDbResponse<T> = response.body;
|
||||
|
||||
// Check meta status
|
||||
if (data?.meta?.status === 'error') {
|
||||
this.logger.log('error', `API returned error: ${data.meta.message}`);
|
||||
throw new Error(`PeeringDB API error: ${data.meta.message}`);
|
||||
}
|
||||
|
||||
// Handle pagination if autoPaginate is enabled
|
||||
if (options.autoPaginate && data.data.length === (options.limit || 0)) {
|
||||
const allResults = [...data.data];
|
||||
let currentSkip = (options.skip || 0) + data.data.length;
|
||||
|
||||
while (true) {
|
||||
const nextOptions = { ...options, skip: currentSkip };
|
||||
const nextUrl = this.buildUrl(endpoint, nextOptions);
|
||||
|
||||
const nextResponse = await smartrequest.SmartRequestClient.create()
|
||||
.url(nextUrl)
|
||||
.header('Accept', 'application/json')
|
||||
.header('User-Agent', '@apiclient.xyz/peeringdb/1.0.1 (Node.js)')
|
||||
.header('Authorization', this.apiKey ? `Api-Key ${this.apiKey}` : '')
|
||||
.retry(3)
|
||||
.get();
|
||||
|
||||
const nextData: IPeeringDbResponse<T> = nextResponse.body;
|
||||
|
||||
if (nextData.data.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
allResults.push(...nextData.data);
|
||||
currentSkip += nextData.data.length;
|
||||
|
||||
// Safety check to prevent infinite loops
|
||||
if (nextData.data.length < (options.limit || 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return allResults;
|
||||
}
|
||||
|
||||
// Return unwrapped data array
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
this.logger.log('error', `Request failed: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build API URL with query parameters
|
||||
*/
|
||||
private buildUrl(endpoint: string, options: IQueryOptions = {}): string {
|
||||
const url = new URL(`${this.baseUrl}/${endpoint}`);
|
||||
|
||||
// Add standard query parameters
|
||||
if (options.limit !== undefined) {
|
||||
url.searchParams.set('limit', options.limit.toString());
|
||||
}
|
||||
|
||||
if (options.skip !== undefined) {
|
||||
url.searchParams.set('skip', options.skip.toString());
|
||||
}
|
||||
|
||||
if (options.fields) {
|
||||
url.searchParams.set('fields', options.fields);
|
||||
}
|
||||
|
||||
if (options.depth !== undefined) {
|
||||
url.searchParams.set('depth', options.depth.toString());
|
||||
}
|
||||
|
||||
if (options.since !== undefined) {
|
||||
url.searchParams.set('since', options.since.toString());
|
||||
}
|
||||
|
||||
// Add any additional query parameters (field filters, etc.)
|
||||
Object.keys(options).forEach((key) => {
|
||||
if (
|
||||
!['limit', 'skip', 'fields', 'depth', 'since', 'autoPaginate'].includes(key)
|
||||
) {
|
||||
const value = options[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
url.searchParams.set(key, value.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience methods for common operations
|
||||
*/
|
||||
public convenience = {
|
||||
/**
|
||||
* Get a network by ASN
|
||||
*/
|
||||
getNetworkByAsn: async (asn: number) => {
|
||||
const results = await this.request('net', 'GET', { asn });
|
||||
return results[0] || null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get an organization by ID
|
||||
*/
|
||||
getOrganizationById: async (id: number) => {
|
||||
return this.organizations.getById(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a facility by ID
|
||||
*/
|
||||
getFacilityById: async (id: number) => {
|
||||
return this.facilities.getById(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get an exchange by ID
|
||||
*/
|
||||
getExchangeById: async (id: number) => {
|
||||
return this.exchanges.getById(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Search networks by name
|
||||
*/
|
||||
searchNetworks: async (query: string) => {
|
||||
return this.request('net', 'GET', { name__contains: query });
|
||||
},
|
||||
|
||||
/**
|
||||
* Search facilities by name
|
||||
*/
|
||||
searchFacilities: async (query: string) => {
|
||||
return this.request('fac', 'GET', { name__contains: query });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all facilities where a network is present
|
||||
*/
|
||||
getNetworkFacilities: async (asn: number) => {
|
||||
const network = await this.convenience.getNetworkByAsn(asn);
|
||||
if (!network) {
|
||||
return [];
|
||||
}
|
||||
return this.request('netfac', 'GET', { net_id: network.id, depth: 2 });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all exchanges where a network peers
|
||||
*/
|
||||
getNetworkExchanges: async (asn: number) => {
|
||||
const network = await this.convenience.getNetworkByAsn(asn);
|
||||
if (!network) {
|
||||
return [];
|
||||
}
|
||||
return this.request('netixlan', 'GET', { net_id: network.id, depth: 2 });
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all networks present at a facility
|
||||
*/
|
||||
getFacilityNetworks: async (facId: number) => {
|
||||
return this.request('netfac', 'GET', { fac_id: facId, depth: 2 });
|
||||
},
|
||||
};
|
||||
}
|
||||
102
ts/peeringdb.classes.exchangemanager.ts
Normal file
102
ts/peeringdb.classes.exchangemanager.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { IExchange } from './interfaces/peeringdb.api.exchange.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for Internet Exchange resources
|
||||
*/
|
||||
export class ExchangeManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List exchanges with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<IExchange[]> {
|
||||
return this.client.request<IExchange>('ix', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single exchange by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<IExchange | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<IExchange>('ix', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search exchanges by name
|
||||
*/
|
||||
async searchByName(name: string, options: IQueryOptions = {}): Promise<IExchange[]> {
|
||||
return this.client.request<IExchange>('ix', 'GET', {
|
||||
...options,
|
||||
name__contains: name,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get exchanges by country
|
||||
*/
|
||||
async getByCountry(country: string, options: IQueryOptions = {}): Promise<IExchange[]> {
|
||||
return this.client.request<IExchange>('ix', 'GET', {
|
||||
...options,
|
||||
country,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get exchanges by city
|
||||
*/
|
||||
async getByCity(city: string, options: IQueryOptions = {}): Promise<IExchange[]> {
|
||||
return this.client.request<IExchange>('ix', 'GET', {
|
||||
...options,
|
||||
city__contains: city,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get exchanges by region/continent
|
||||
*/
|
||||
async getByRegion(region: string, options: IQueryOptions = {}): Promise<IExchange[]> {
|
||||
return this.client.request<IExchange>('ix', 'GET', {
|
||||
...options,
|
||||
region_continent: region,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get exchanges by organization ID
|
||||
*/
|
||||
async getByOrgId(orgId: number, options: IQueryOptions = {}): Promise<IExchange[]> {
|
||||
return this.client.request<IExchange>('ix', 'GET', {
|
||||
...options,
|
||||
org_id: orgId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new exchange (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<IExchange>): Promise<IExchange> {
|
||||
const results = await this.client.request<IExchange>('ix', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an exchange (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<IExchange>): Promise<IExchange> {
|
||||
const results = await this.client.request<IExchange>(`ix/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an exchange (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('ix', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
92
ts/peeringdb.classes.facilitymanager.ts
Normal file
92
ts/peeringdb.classes.facilitymanager.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { IFacility } from './interfaces/peeringdb.api.facility.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for Facility resources
|
||||
*/
|
||||
export class FacilityManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List facilities with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<IFacility[]> {
|
||||
return this.client.request<IFacility>('fac', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single facility by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<IFacility | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<IFacility>('fac', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search facilities by name
|
||||
*/
|
||||
async searchByName(name: string, options: IQueryOptions = {}): Promise<IFacility[]> {
|
||||
return this.client.request<IFacility>('fac', 'GET', {
|
||||
...options,
|
||||
name__contains: name,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get facilities by country
|
||||
*/
|
||||
async getByCountry(country: string, options: IQueryOptions = {}): Promise<IFacility[]> {
|
||||
return this.client.request<IFacility>('fac', 'GET', {
|
||||
...options,
|
||||
country,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get facilities by city
|
||||
*/
|
||||
async getByCity(city: string, options: IQueryOptions = {}): Promise<IFacility[]> {
|
||||
return this.client.request<IFacility>('fac', 'GET', {
|
||||
...options,
|
||||
city__contains: city,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get facilities by organization ID
|
||||
*/
|
||||
async getByOrgId(orgId: number, options: IQueryOptions = {}): Promise<IFacility[]> {
|
||||
return this.client.request<IFacility>('fac', 'GET', {
|
||||
...options,
|
||||
org_id: orgId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new facility (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<IFacility>): Promise<IFacility> {
|
||||
const results = await this.client.request<IFacility>('fac', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a facility (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<IFacility>): Promise<IFacility> {
|
||||
const results = await this.client.request<IFacility>(`fac/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a facility (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('fac', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
72
ts/peeringdb.classes.ixfacmanager.ts
Normal file
72
ts/peeringdb.classes.ixfacmanager.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { IIxFac } from './interfaces/peeringdb.api.ixfac.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for IxFac resources (IX-facility connections)
|
||||
*/
|
||||
export class IxFacManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List IX-facility connections with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<IIxFac[]> {
|
||||
return this.client.request<IIxFac>('ixfac', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single IX-facility connection by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<IIxFac | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<IIxFac>('ixfac', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IX-facility connections by exchange ID
|
||||
*/
|
||||
async getByIxId(ixId: number, options: IQueryOptions = {}): Promise<IIxFac[]> {
|
||||
return this.client.request<IIxFac>('ixfac', 'GET', {
|
||||
...options,
|
||||
ix_id: ixId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IX-facility connections by facility ID
|
||||
*/
|
||||
async getByFacId(facId: number, options: IQueryOptions = {}): Promise<IIxFac[]> {
|
||||
return this.client.request<IIxFac>('ixfac', 'GET', {
|
||||
...options,
|
||||
fac_id: facId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new IX-facility connection (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<IIxFac>): Promise<IIxFac> {
|
||||
const results = await this.client.request<IIxFac>('ixfac', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an IX-facility connection (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<IIxFac>): Promise<IIxFac> {
|
||||
const results = await this.client.request<IIxFac>(`ixfac/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an IX-facility connection (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('ixfac', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
62
ts/peeringdb.classes.ixlanmanager.ts
Normal file
62
ts/peeringdb.classes.ixlanmanager.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { IIxLan } from './interfaces/peeringdb.api.ixlan.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for IxLan resources (IX LAN information)
|
||||
*/
|
||||
export class IxLanManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List IX LANs with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<IIxLan[]> {
|
||||
return this.client.request<IIxLan>('ixlan', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single IX LAN by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<IIxLan | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<IIxLan>('ixlan', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IX LANs by exchange ID
|
||||
*/
|
||||
async getByIxId(ixId: number, options: IQueryOptions = {}): Promise<IIxLan[]> {
|
||||
return this.client.request<IIxLan>('ixlan', 'GET', {
|
||||
...options,
|
||||
ix_id: ixId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new IX LAN (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<IIxLan>): Promise<IIxLan> {
|
||||
const results = await this.client.request<IIxLan>('ixlan', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an IX LAN (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<IIxLan>): Promise<IIxLan> {
|
||||
const results = await this.client.request<IIxLan>(`ixlan/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an IX LAN (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('ixlan', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
72
ts/peeringdb.classes.ixpfxmanager.ts
Normal file
72
ts/peeringdb.classes.ixpfxmanager.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { IIxPfx } from './interfaces/peeringdb.api.ixpfx.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for IxPfx resources (IX IP prefixes)
|
||||
*/
|
||||
export class IxPfxManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List IX prefixes with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<IIxPfx[]> {
|
||||
return this.client.request<IIxPfx>('ixpfx', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single IX prefix by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<IIxPfx | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<IIxPfx>('ixpfx', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IX prefixes by IX LAN ID
|
||||
*/
|
||||
async getByIxLanId(ixlanId: number, options: IQueryOptions = {}): Promise<IIxPfx[]> {
|
||||
return this.client.request<IIxPfx>('ixpfx', 'GET', {
|
||||
...options,
|
||||
ixlan_id: ixlanId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IX prefixes by protocol (IPv4/IPv6)
|
||||
*/
|
||||
async getByProtocol(protocol: string, options: IQueryOptions = {}): Promise<IIxPfx[]> {
|
||||
return this.client.request<IIxPfx>('ixpfx', 'GET', {
|
||||
...options,
|
||||
protocol,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new IX prefix (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<IIxPfx>): Promise<IIxPfx> {
|
||||
const results = await this.client.request<IIxPfx>('ixpfx', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an IX prefix (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<IIxPfx>): Promise<IIxPfx> {
|
||||
const results = await this.client.request<IIxPfx>(`ixpfx/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an IX prefix (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('ixpfx', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
72
ts/peeringdb.classes.netfacmanager.ts
Normal file
72
ts/peeringdb.classes.netfacmanager.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { INetFac } from './interfaces/peeringdb.api.netfac.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for NetFac resources (network presence at facility)
|
||||
*/
|
||||
export class NetFacManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List network-facility connections with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<INetFac[]> {
|
||||
return this.client.request<INetFac>('netfac', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single network-facility connection by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<INetFac | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<INetFac>('netfac', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network-facility connections by network ID
|
||||
*/
|
||||
async getByNetId(netId: number, options: IQueryOptions = {}): Promise<INetFac[]> {
|
||||
return this.client.request<INetFac>('netfac', 'GET', {
|
||||
...options,
|
||||
net_id: netId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network-facility connections by facility ID
|
||||
*/
|
||||
async getByFacId(facId: number, options: IQueryOptions = {}): Promise<INetFac[]> {
|
||||
return this.client.request<INetFac>('netfac', 'GET', {
|
||||
...options,
|
||||
fac_id: facId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new network-facility connection (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<INetFac>): Promise<INetFac> {
|
||||
const results = await this.client.request<INetFac>('netfac', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a network-facility connection (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<INetFac>): Promise<INetFac> {
|
||||
const results = await this.client.request<INetFac>(`netfac/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a network-facility connection (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('netfac', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
82
ts/peeringdb.classes.netixlanmanager.ts
Normal file
82
ts/peeringdb.classes.netixlanmanager.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { INetIxLan } from './interfaces/peeringdb.api.netixlan.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for NetIxLan resources (network presence at IX)
|
||||
*/
|
||||
export class NetIxLanManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List network-IX connections with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<INetIxLan[]> {
|
||||
return this.client.request<INetIxLan>('netixlan', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single network-IX connection by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<INetIxLan | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<INetIxLan>('netixlan', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network-IX connections by network ID
|
||||
*/
|
||||
async getByNetId(netId: number, options: IQueryOptions = {}): Promise<INetIxLan[]> {
|
||||
return this.client.request<INetIxLan>('netixlan', 'GET', {
|
||||
...options,
|
||||
net_id: netId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network-IX connections by IX LAN ID
|
||||
*/
|
||||
async getByIxLanId(ixlanId: number, options: IQueryOptions = {}): Promise<INetIxLan[]> {
|
||||
return this.client.request<INetIxLan>('netixlan', 'GET', {
|
||||
...options,
|
||||
ixlan_id: ixlanId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network-IX connections by ASN
|
||||
*/
|
||||
async getByAsn(asn: number, options: IQueryOptions = {}): Promise<INetIxLan[]> {
|
||||
return this.client.request<INetIxLan>('netixlan', 'GET', {
|
||||
...options,
|
||||
asn,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new network-IX connection (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<INetIxLan>): Promise<INetIxLan> {
|
||||
const results = await this.client.request<INetIxLan>('netixlan', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a network-IX connection (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<INetIxLan>): Promise<INetIxLan> {
|
||||
const results = await this.client.request<INetIxLan>(`netixlan/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a network-IX connection (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('netixlan', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
104
ts/peeringdb.classes.networkmanager.ts
Normal file
104
ts/peeringdb.classes.networkmanager.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { INetwork } from './interfaces/peeringdb.api.network.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for Network resources
|
||||
*/
|
||||
export class NetworkManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List networks with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<INetwork[]> {
|
||||
return this.client.request<INetwork>('net', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single network by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<INetwork | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<INetwork>('net', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a network by ASN
|
||||
*/
|
||||
async getByAsn(asn: number, depth?: 0 | 1 | 2): Promise<INetwork | null> {
|
||||
const options: IQueryOptions = { asn };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<INetwork>('net', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search networks by name
|
||||
*/
|
||||
async searchByName(name: string, options: IQueryOptions = {}): Promise<INetwork[]> {
|
||||
return this.client.request<INetwork>('net', 'GET', {
|
||||
...options,
|
||||
name__contains: name,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get networks by organization ID
|
||||
*/
|
||||
async getByOrgId(orgId: number, options: IQueryOptions = {}): Promise<INetwork[]> {
|
||||
return this.client.request<INetwork>('net', 'GET', {
|
||||
...options,
|
||||
org_id: orgId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Search networks by IRR as-set
|
||||
*/
|
||||
async searchByIrrAsSet(irrAsSet: string, options: IQueryOptions = {}): Promise<INetwork[]> {
|
||||
return this.client.request<INetwork>('net', 'GET', {
|
||||
...options,
|
||||
irr_as_set__contains: irrAsSet,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get networks by peering policy
|
||||
*/
|
||||
async getByPolicy(policy: string, options: IQueryOptions = {}): Promise<INetwork[]> {
|
||||
return this.client.request<INetwork>('net', 'GET', {
|
||||
...options,
|
||||
policy_general: policy,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new network (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<INetwork>): Promise<INetwork> {
|
||||
const results = await this.client.request<INetwork>('net', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a network (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<INetwork>): Promise<INetwork> {
|
||||
const results = await this.client.request<INetwork>(`net/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a network (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('net', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
72
ts/peeringdb.classes.organizationmanager.ts
Normal file
72
ts/peeringdb.classes.organizationmanager.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { IOrganization } from './interfaces/peeringdb.api.organization.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for Organization resources
|
||||
*/
|
||||
export class OrganizationManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List organizations with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<IOrganization[]> {
|
||||
return this.client.request<IOrganization>('org', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single organization by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<IOrganization | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<IOrganization>('org', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search organizations by name
|
||||
*/
|
||||
async searchByName(name: string, options: IQueryOptions = {}): Promise<IOrganization[]> {
|
||||
return this.client.request<IOrganization>('org', 'GET', {
|
||||
...options,
|
||||
name__contains: name,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get organizations by country
|
||||
*/
|
||||
async getByCountry(country: string, options: IQueryOptions = {}): Promise<IOrganization[]> {
|
||||
return this.client.request<IOrganization>('org', 'GET', {
|
||||
...options,
|
||||
country,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new organization (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<IOrganization>): Promise<IOrganization> {
|
||||
const results = await this.client.request<IOrganization>('org', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an organization (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<IOrganization>): Promise<IOrganization> {
|
||||
const results = await this.client.request<IOrganization>(`org/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an organization (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('org', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
72
ts/peeringdb.classes.pocmanager.ts
Normal file
72
ts/peeringdb.classes.pocmanager.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { PeeringDbClient } from './peeringdb.classes.client.js';
|
||||
import type { IPointOfContact } from './interfaces/peeringdb.api.poc.js';
|
||||
import type { IQueryOptions } from './peeringdb.types.js';
|
||||
|
||||
/**
|
||||
* Manager for Point of Contact resources
|
||||
*/
|
||||
export class PocManager {
|
||||
constructor(private client: PeeringDbClient) {}
|
||||
|
||||
/**
|
||||
* List points of contact with optional filtering
|
||||
*/
|
||||
async list(options: IQueryOptions = {}): Promise<IPointOfContact[]> {
|
||||
return this.client.request<IPointOfContact>('poc', 'GET', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single point of contact by ID
|
||||
*/
|
||||
async getById(id: number, depth?: 0 | 1 | 2): Promise<IPointOfContact | null> {
|
||||
const options: IQueryOptions = { id };
|
||||
if (depth !== undefined) {
|
||||
options.depth = depth;
|
||||
}
|
||||
const results = await this.client.request<IPointOfContact>('poc', 'GET', options);
|
||||
return results[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get points of contact by network ID
|
||||
*/
|
||||
async getByNetId(netId: number, options: IQueryOptions = {}): Promise<IPointOfContact[]> {
|
||||
return this.client.request<IPointOfContact>('poc', 'GET', {
|
||||
...options,
|
||||
net_id: netId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get points of contact by role
|
||||
*/
|
||||
async getByRole(role: string, options: IQueryOptions = {}): Promise<IPointOfContact[]> {
|
||||
return this.client.request<IPointOfContact>('poc', 'GET', {
|
||||
...options,
|
||||
role__contains: role,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new point of contact (requires authentication)
|
||||
*/
|
||||
async create(data: Partial<IPointOfContact>): Promise<IPointOfContact> {
|
||||
const results = await this.client.request<IPointOfContact>('poc', 'POST', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a point of contact (requires authentication)
|
||||
*/
|
||||
async update(id: number, data: Partial<IPointOfContact>): Promise<IPointOfContact> {
|
||||
const results = await this.client.request<IPointOfContact>(`poc/${id}`, 'PUT', {}, data);
|
||||
return results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a point of contact (requires authentication)
|
||||
*/
|
||||
async delete(id: number): Promise<void> {
|
||||
await this.client.request('poc', 'DELETE', { id });
|
||||
}
|
||||
}
|
||||
108
ts/peeringdb.types.ts
Normal file
108
ts/peeringdb.types.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Core types for PeeringDB API client
|
||||
*/
|
||||
|
||||
/**
|
||||
* HTTP methods supported by the API
|
||||
*/
|
||||
export type THttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
|
||||
/**
|
||||
* Depth levels for nested object expansion
|
||||
* - 0: No expansion (IDs only)
|
||||
* - 1: Expand to IDs for related objects
|
||||
* - 2: Full object expansion for related objects
|
||||
*/
|
||||
export type TDepth = 0 | 1 | 2;
|
||||
|
||||
/**
|
||||
* Meta information returned by the PeeringDB API
|
||||
*/
|
||||
export interface IPeeringDbMeta {
|
||||
status: 'ok' | 'error';
|
||||
message?: string;
|
||||
generated?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard API response wrapper from PeeringDB
|
||||
*/
|
||||
export interface IPeeringDbResponse<T> {
|
||||
meta: IPeeringDbMeta;
|
||||
data: T[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Query options for API requests
|
||||
*/
|
||||
export interface IQueryOptions {
|
||||
/** Limit the number of results */
|
||||
limit?: number;
|
||||
|
||||
/** Skip/offset for pagination */
|
||||
skip?: number;
|
||||
|
||||
/** Comma-separated list of fields to return */
|
||||
fields?: string;
|
||||
|
||||
/** Depth of nested object expansion (0, 1, or 2) */
|
||||
depth?: TDepth;
|
||||
|
||||
/** Unix timestamp - only return objects updated since this time */
|
||||
since?: number;
|
||||
|
||||
/** Auto-paginate through all results (default: false) */
|
||||
autoPaginate?: boolean;
|
||||
|
||||
/** Additional query parameters (field filters, etc.) */
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field filter operators for string fields
|
||||
*/
|
||||
export interface IStringFilters {
|
||||
/** Field contains value */
|
||||
__contains?: string;
|
||||
|
||||
/** Field starts with value */
|
||||
__startswith?: string;
|
||||
|
||||
/** Field is in list of values */
|
||||
__in?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Field filter operators for number fields
|
||||
*/
|
||||
export interface INumberFilters {
|
||||
/** Field is less than value */
|
||||
__lt?: number;
|
||||
|
||||
/** Field is less than or equal to value */
|
||||
__lte?: number;
|
||||
|
||||
/** Field is greater than value */
|
||||
__gt?: number;
|
||||
|
||||
/** Field is greater than or equal to value */
|
||||
__gte?: number;
|
||||
|
||||
/** Field is in list of values */
|
||||
__in?: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Base fields present in all PeeringDB objects
|
||||
*/
|
||||
export interface IPeeringDbBaseObject {
|
||||
id: number;
|
||||
status: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common status values for PeeringDB objects
|
||||
*/
|
||||
export type TStatus = 'ok' | 'pending' | 'deleted';
|
||||
5
ts/plugins.ts
Normal file
5
ts/plugins.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
// push.rocks scope
|
||||
import * as smartlog from '@push.rocks/smartlog';
|
||||
import * as smartrequest from '@push.rocks/smartrequest';
|
||||
|
||||
export { smartlog, smartrequest };
|
||||
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {}
|
||||
},
|
||||
"exclude": ["dist_*/**/*.d.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user