https://github.com/wyre-technology/node-it-glue
Comprehensive, fully-typed Node.js/TypeScript library for the IT Glue API
https://github.com/wyre-technology/node-it-glue
itglue msp nodejs sdk typescript wyre-technology
Last synced: 2 months ago
JSON representation
Comprehensive, fully-typed Node.js/TypeScript library for the IT Glue API
- Host: GitHub
- URL: https://github.com/wyre-technology/node-it-glue
- Owner: wyre-technology
- License: apache-2.0
- Created: 2026-02-04T23:44:28.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-25T21:22:29.000Z (3 months ago)
- Last Synced: 2026-03-26T20:45:15.700Z (3 months ago)
- Topics: itglue, msp, nodejs, sdk, typescript, wyre-technology
- Language: TypeScript
- Homepage: https://github.com/wyre-technology/node-it-glue/packages
- Size: 197 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# node-it-glue
Comprehensive, fully-typed Node.js/TypeScript library for the IT Glue API.
## Features
- **Complete API coverage** - Every documented IT Glue endpoint is implemented
- **Strong TypeScript types** - Full type definitions for all request/response payloads
- **JSON:API abstraction** - Unwrap the JSON:API envelope so consumers work with clean objects
- **Automatic pagination** - Iterator/generator patterns for seamless multi-page retrieval
- **Rate limit handling** - Built-in request throttling (3000 req / 5 min) with backoff
- **Zero live API testing** - Full test suite with mocked HTTP responses
## Installation
```bash
npm install node-it-glue
```
## Quick Start
```typescript
import { ITGlueClient } from 'node-it-glue';
const client = new ITGlueClient({
apiKey: 'ITG.xxxxxxxxxxxxxxxxxxxxxxxx',
region: 'us', // 'us' | 'eu' | 'au'
});
// List organizations
const { data, meta } = await client.organizations.list({
filter: { organizationStatusId: 1 },
page: { size: 50 },
});
console.log(`Found ${meta.totalCount} organizations`);
for (const org of data) {
console.log(org.name);
}
// Auto-paginate all configurations for an org
for await (const config of client.configurations.listAll({
filter: { organizationId: 12345 },
})) {
console.log(config.name, config.serialNumber);
}
```
## Configuration
```typescript
const client = new ITGlueClient({
apiKey: 'ITG.xxxxxxxxxxxxxxxxxxxxxxxx', // Required
region: 'us', // 'us' | 'eu' | 'au' (default: 'us')
// OR explicit base URL:
// baseUrl: 'https://api.itglue.com',
timeout: 30000, // Request timeout in ms (default: 30000)
rateLimiter: { // Rate limiting options
enabled: true, // Enable rate limiting (default: true)
maxRequests: 3000, // Max requests per window (default: 3000)
windowMs: 300000, // Window duration in ms (default: 5 minutes)
throttleThreshold: 0.8, // Start throttling at 80% (default: 0.8)
retryAfterMs: 5000, // Retry delay (default: 5000)
maxRetries: 3 // Max retry attempts (default: 3)
}
});
```
### Regional Base URLs
| Region | Base URL |
|--------|----------|
| `us` | `https://api.itglue.com` |
| `eu` | `https://api.eu.itglue.com` |
| `au` | `https://api.au.itglue.com` |
## Pagination
All list methods return paginated results. You can manually paginate:
```typescript
const page1 = await client.organizations.list({ page: { size: 50, number: 1 } });
const page2 = await client.organizations.list({ page: { size: 50, number: 2 } });
```
Or use automatic pagination with async iterators:
```typescript
// Iterate through all items
for await (const org of client.organizations.listAll()) {
console.log(org.name);
}
// Collect all into an array
const allOrgs = await client.organizations.listAll().toArray();
```
## Filtering
IT Glue supports extensive filtering options:
```typescript
const orgs = await client.organizations.list({
filter: {
name: 'Acme',
organizationTypeId: 42,
organizationStatusId: 1,
excludeId: [100, 200],
createdAt: { gt: '2024-01-01' },
updatedAt: { lt: '2025-01-01' },
},
sort: 'name', // or '-name' for descending
page: { size: 100, number: 1 },
include: 'locations', // sideload related resources
});
```
## Error Handling
The library provides typed error classes for different error scenarios:
```typescript
import {
ITGlueClient,
ITGlueNotFoundError,
ITGlueValidationError,
ITGlueAuthenticationError,
ITGlueRateLimitError,
} from 'node-it-glue';
try {
await client.organizations.get('12345');
} catch (error) {
if (error instanceof ITGlueNotFoundError) {
console.error('Organization not found');
} else if (error instanceof ITGlueValidationError) {
console.error('Validation errors:', error.getErrorMessages());
} else if (error instanceof ITGlueAuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof ITGlueRateLimitError) {
console.error('Rate limited, retry after:', error.retryAfter);
} else {
throw error;
}
}
```
## Available Resources
### Organizations
```typescript
// List
const { data, meta } = await client.organizations.list(params?);
// List all (auto-paginate)
for await (const org of client.organizations.listAll(params?)) { }
// Get
const org = await client.organizations.get(id, params?);
// Create
const newOrg = await client.organizations.create(data);
// Update
const updated = await client.organizations.update(id, data);
// Delete
await client.organizations.delete(id);
```
### Organization Types
```typescript
const { data } = await client.organizationTypes.list(params?);
const newType = await client.organizationTypes.create(data);
const updated = await client.organizationTypes.update(id, data);
```
### Organization Statuses
```typescript
const { data } = await client.organizationStatuses.list(params?);
const newStatus = await client.organizationStatuses.create(data);
const updated = await client.organizationStatuses.update(id, data);
```
### Configurations
```typescript
// List all configurations
const { data } = await client.configurations.list();
// List configurations for an organization
const { data } = await client.configurations.listByOrg(orgId);
// Get with related data
const config = await client.configurations.get(id, {
include: 'configuration_interfaces,related_items',
});
// Create
const newConfig = await client.configurations.create({
organizationId: 123,
configurationTypeId: 1,
name: 'Server-01',
});
```
### Configuration Types, Statuses, Interfaces
```typescript
// Configuration Types
const { data } = await client.configurationTypes.list();
const type = await client.configurationTypes.create({ name: 'Server' });
// Configuration Statuses
const { data } = await client.configurationStatuses.list();
const status = await client.configurationStatuses.create({ name: 'Active' });
// Configuration Interfaces (nested under configurations)
const { data } = await client.configurationInterfaces.listByConfig(configId);
const iface = await client.configurationInterfaces.create({
configurationId: 123,
name: 'eth0',
ipAddress: '192.168.1.1',
});
```
### Contacts
```typescript
// List contacts
const { data } = await client.contacts.list();
// List contacts for an organization
const { data } = await client.contacts.listByOrg(orgId);
// Create a contact
const contact = await client.contacts.create({
organizationId: 123,
firstName: 'John',
lastName: 'Doe',
contactTypeId: 1,
});
```
### Contact Types
```typescript
const { data } = await client.contactTypes.list();
const type = await client.contactTypes.create({ name: 'Technical' });
```
### Documents
```typescript
// List documents
const { data } = await client.documents.list();
// List documents for an organization
const { data } = await client.documents.listByOrg(orgId);
// Create a document
const doc = await client.documents.create({
organizationId: 123,
name: 'Network Diagram',
});
// Publish a document
await client.documents.publish(docId);
```
### Document Sections and Images
```typescript
// Document Sections
const { data } = await client.documentSections.listByDoc(docId);
const section = await client.documentSections.create(docId, {
name: 'Overview',
content: '
Introduction...
',
});
// Document Images
const { data } = await client.documentImages.list();
const image = await client.documentImages.create({
documentId: 123,
content: base64ImageData,
});
```
### Passwords
```typescript
// List passwords (values hidden by default)
const { data } = await client.passwords.list();
// List passwords with values visible
const { data } = await client.passwords.list({ showPassword: true });
// Get a password with value
const pwd = await client.passwords.get(id, { showPassword: true });
// Create a password
const newPwd = await client.passwords.create({
organizationId: 123,
name: 'Admin Password',
password: 'secret123',
passwordCategoryId: 1,
});
```
### Password Categories and Folders
```typescript
// Password Categories
const { data } = await client.passwordCategories.list();
const cat = await client.passwordCategories.create({ name: 'Server Credentials' });
// Password Folders (nested under organizations)
const { data } = await client.passwordFolders.listByOrg(orgId);
const folder = await client.passwordFolders.create(orgId, { name: 'Production' });
```
### Flexible Assets
```typescript
// List flexible asset types
const { data: types } = await client.flexibleAssetTypes.list();
// List flexible assets (requires filter)
const { data } = await client.flexibleAssets.list({
filter: { flexibleAssetTypeId: 123 },
});
// Create a flexible asset
const asset = await client.flexibleAssets.create({
organizationId: 123,
flexibleAssetTypeId: 456,
traits: {
'custom-field-1': 'value1',
'custom-field-2': 'value2',
},
});
```
### Flexible Asset Types and Fields
```typescript
// Flexible Asset Types
const { data } = await client.flexibleAssetTypes.list();
const type = await client.flexibleAssetTypes.create({
name: 'Network Documentation',
icon: 'sitemap',
});
// Flexible Asset Fields (nested under types)
const { data } = await client.flexibleAssetFields.listByType(typeId);
const field = await client.flexibleAssetFields.create({
flexibleAssetTypeId: 123,
name: 'IP Range',
kind: 'Text',
});
```
### Locations
```typescript
// List locations for an organization
const { data } = await client.locations.listByOrg(orgId);
// Create a location
const loc = await client.locations.create({
organizationId: 123,
name: 'Main Office',
addressLine1: '123 Main St',
city: 'Springfield',
postalCode: '12345',
countryId: 1,
regionId: 1,
});
```
### Users and Groups
```typescript
// Users (read-only creation, can update)
const { data } = await client.users.list();
const user = await client.users.get(userId);
const updated = await client.users.update(userId, { firstName: 'Jane' });
// Bulk update users
const results = await client.users.bulkUpdate({
users: [
{ id: 1, firstName: 'Jane' },
{ id: 2, lastName: 'Smith' },
],
});
// User Metrics
const { data } = await client.userMetrics.list({
filter: { userId: 123, date: '2024-01-01' },
});
// Groups
const { data } = await client.groups.list();
const group = await client.groups.create({ name: 'Admins' });
```
### Metadata Resources
```typescript
// Manufacturers
const { data } = await client.manufacturers.list();
const mfg = await client.manufacturers.create({ name: 'Dell' });
// Models (nested under manufacturers)
const { data } = await client.models.listByManufacturer(mfgId);
const model = await client.models.create({ manufacturerId: 1, name: 'PowerEdge R640' });
// Platforms (read-only)
const { data } = await client.platforms.list();
// Operating Systems (read-only)
const { data } = await client.operatingSystems.list();
// Countries (read-only)
const { data } = await client.countries.list();
const country = await client.countries.get(countryId);
// Regions (nested under countries, read-only)
const { data } = await client.regions.listByCountry(countryId);
```
### Miscellaneous Resources
```typescript
// Domains (nested under organizations, read-only)
const { data } = await client.domains.listByOrg(orgId);
// Expirations (read-only)
const { data } = await client.expirations.list();
const exp = await client.expirations.get(expId);
// Logs (read-only)
const { data } = await client.logs.list();
for await (const log of client.logs.listAll()) {
console.log(log.action);
}
// Attachments (nested under various resources)
const { data } = await client.attachments.list('configurations', configId);
const att = await client.attachments.create('configurations', configId, {
name: 'diagram.png',
content: base64Data,
});
await client.attachments.delete('configurations', configId, attachmentId);
// Related Items
await client.relatedItems.create('configurations', configId, {
destinationType: 'passwords',
destinationId: passwordId,
});
await client.relatedItems.delete('configurations', configId, relatedItemId);
// Exports
const exportJob = await client.exports.create({
organizationIds: [123, 456],
includePasswords: true,
});
const status = await client.exports.get(exportJob.id);
// Checklists (nested under organizations)
const { data } = await client.checklists.listByOrg(orgId);
const checklist = await client.checklists.get(checklistId);
const updated = await client.checklists.update(checklistId, { completed: true });
```
## Complete Resource Reference
| Resource | Methods |
|----------|---------|
| `organizations` | list, listAll, get, create, update, delete |
| `organizationTypes` | list, listAll, get, create, update |
| `organizationStatuses` | list, listAll, get, create, update |
| `configurations` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete |
| `configurationTypes` | list, listAll, get, create, update, delete |
| `configurationStatuses` | list, listAll, get, create, update, delete |
| `configurationInterfaces` | listByConfig, create, update, delete |
| `contacts` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete |
| `contactTypes` | list, listAll, get, create, update |
| `documents` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete, publish |
| `documentSections` | listByDoc, create, update, delete |
| `documentImages` | list, create, delete |
| `passwords` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete |
| `passwordCategories` | list, listAll, get, create, update, delete |
| `passwordFolders` | listByOrg, create, update, delete |
| `flexibleAssetTypes` | list, listAll, get, create, update, delete |
| `flexibleAssetFields` | listByType, create, update, delete |
| `flexibleAssets` | list, listAll, get, create, update, delete |
| `locations` | listByOrg, create, update, delete |
| `users` | list, listAll, get, update, bulkUpdate |
| `userMetrics` | list, listAll |
| `groups` | list, listAll, get, create, update, delete |
| `manufacturers` | list, listAll, get, create, update |
| `models` | listByManufacturer, create, update |
| `platforms` | list |
| `operatingSystems` | list |
| `countries` | list, listAll, get |
| `regions` | listByCountry |
| `domains` | listByOrg |
| `expirations` | list, listAll, get |
| `logs` | list, listAll |
| `attachments` | list, create, update, delete |
| `relatedItems` | create, update, delete |
| `exports` | list, listAll, get, create, delete |
| `checklists` | listByOrg, get, update, delete |
## Rate Limiting
The library automatically handles IT Glue's rate limits (3000 requests per 5 minutes):
- **Request tracking** - Counts requests within the rolling window
- **Preemptive throttling** - Slows down when approaching the limit (default: 80%)
- **429 handling** - Automatically retries with exponential backoff
- **Configurable** - Adjust thresholds or disable entirely
Monitor rate limit status:
```typescript
const status = client.getRateLimitStatus();
console.log(`Requests: ${status.currentCount}/${status.maxRequests}`);
console.log(`Remaining: ${status.remaining}`);
console.log(`Is throttling: ${status.isThrottling}`);
```
## JSON:API Handling
IT Glue uses the JSON:API specification. This library transparently handles:
- **Deserialization** - Flattens `attributes` and converts kebab-case to camelCase
- **Serialization** - Wraps data in JSON:API envelope for POST/PATCH requests
- **Relationships** - Preserves relationship links in a normalized format
- **Pagination meta** - Converts pagination info to camelCase
Raw API response:
```json
{
"data": {
"id": "123",
"type": "organizations",
"attributes": {
"name": "Acme Corp",
"organization-type-name": "Customer",
"created-at": "2024-01-15T10:30:00.000Z"
}
}
}
```
Deserialized client response:
```typescript
{
id: '123',
type: 'organizations',
name: 'Acme Corp',
organizationTypeName: 'Customer',
createdAt: '2024-01-15T10:30:00.000Z'
}
```
## Development
```bash
# Install dependencies
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Type checking
npm run typecheck
# Build
npm run build
```
## License
Apache-2.0
## Contributing
Contributions are welcome! Please read our contributing guidelines before submitting a pull request.