{"id":47702919,"url":"https://github.com/wyre-technology/node-it-glue","last_synced_at":"2026-04-02T17:44:04.729Z","repository":{"id":336563426,"uuid":"1150143600","full_name":"wyre-technology/node-it-glue","owner":"wyre-technology","description":"Comprehensive, fully-typed Node.js/TypeScript library for the IT Glue API","archived":false,"fork":false,"pushed_at":"2026-03-25T21:22:29.000Z","size":202,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-26T20:45:15.700Z","etag":null,"topics":["itglue","msp","nodejs","sdk","typescript","wyre-technology"],"latest_commit_sha":null,"homepage":"https://github.com/wyre-technology/node-it-glue/packages","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wyre-technology.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-04T23:44:28.000Z","updated_at":"2026-03-25T21:22:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/wyre-technology/node-it-glue","commit_stats":null,"previous_names":["asachs01/node-it-glue","wyre-technology/node-it-glue"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/wyre-technology/node-it-glue","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyre-technology%2Fnode-it-glue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyre-technology%2Fnode-it-glue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyre-technology%2Fnode-it-glue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyre-technology%2Fnode-it-glue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wyre-technology","download_url":"https://codeload.github.com/wyre-technology/node-it-glue/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wyre-technology%2Fnode-it-glue/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31312403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["itglue","msp","nodejs","sdk","typescript","wyre-technology"],"created_at":"2026-04-02T17:44:04.054Z","updated_at":"2026-04-02T17:44:04.715Z","avatar_url":"https://github.com/wyre-technology.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# node-it-glue\n\nComprehensive, fully-typed Node.js/TypeScript library for the IT Glue API.\n\n## Features\n\n- **Complete API coverage** - Every documented IT Glue endpoint is implemented\n- **Strong TypeScript types** - Full type definitions for all request/response payloads\n- **JSON:API abstraction** - Unwrap the JSON:API envelope so consumers work with clean objects\n- **Automatic pagination** - Iterator/generator patterns for seamless multi-page retrieval\n- **Rate limit handling** - Built-in request throttling (3000 req / 5 min) with backoff\n- **Zero live API testing** - Full test suite with mocked HTTP responses\n\n## Installation\n\n```bash\nnpm install node-it-glue\n```\n\n## Quick Start\n\n```typescript\nimport { ITGlueClient } from 'node-it-glue';\n\nconst client = new ITGlueClient({\n  apiKey: 'ITG.xxxxxxxxxxxxxxxxxxxxxxxx',\n  region: 'us', // 'us' | 'eu' | 'au'\n});\n\n// List organizations\nconst { data, meta } = await client.organizations.list({\n  filter: { organizationStatusId: 1 },\n  page: { size: 50 },\n});\n\nconsole.log(`Found ${meta.totalCount} organizations`);\nfor (const org of data) {\n  console.log(org.name);\n}\n\n// Auto-paginate all configurations for an org\nfor await (const config of client.configurations.listAll({\n  filter: { organizationId: 12345 },\n})) {\n  console.log(config.name, config.serialNumber);\n}\n```\n\n## Configuration\n\n```typescript\nconst client = new ITGlueClient({\n  apiKey: 'ITG.xxxxxxxxxxxxxxxxxxxxxxxx', // Required\n  region: 'us',                           // 'us' | 'eu' | 'au' (default: 'us')\n  // OR explicit base URL:\n  // baseUrl: 'https://api.itglue.com',\n  timeout: 30000,                         // Request timeout in ms (default: 30000)\n  rateLimiter: {                          // Rate limiting options\n    enabled: true,                        // Enable rate limiting (default: true)\n    maxRequests: 3000,                    // Max requests per window (default: 3000)\n    windowMs: 300000,                     // Window duration in ms (default: 5 minutes)\n    throttleThreshold: 0.8,               // Start throttling at 80% (default: 0.8)\n    retryAfterMs: 5000,                   // Retry delay (default: 5000)\n    maxRetries: 3                         // Max retry attempts (default: 3)\n  }\n});\n```\n\n### Regional Base URLs\n\n| Region | Base URL |\n|--------|----------|\n| `us`   | `https://api.itglue.com` |\n| `eu`   | `https://api.eu.itglue.com` |\n| `au`   | `https://api.au.itglue.com` |\n\n## Pagination\n\nAll list methods return paginated results. You can manually paginate:\n\n```typescript\nconst page1 = await client.organizations.list({ page: { size: 50, number: 1 } });\nconst page2 = await client.organizations.list({ page: { size: 50, number: 2 } });\n```\n\nOr use automatic pagination with async iterators:\n\n```typescript\n// Iterate through all items\nfor await (const org of client.organizations.listAll()) {\n  console.log(org.name);\n}\n\n// Collect all into an array\nconst allOrgs = await client.organizations.listAll().toArray();\n```\n\n## Filtering\n\nIT Glue supports extensive filtering options:\n\n```typescript\nconst orgs = await client.organizations.list({\n  filter: {\n    name: 'Acme',\n    organizationTypeId: 42,\n    organizationStatusId: 1,\n    excludeId: [100, 200],\n    createdAt: { gt: '2024-01-01' },\n    updatedAt: { lt: '2025-01-01' },\n  },\n  sort: 'name',          // or '-name' for descending\n  page: { size: 100, number: 1 },\n  include: 'locations',  // sideload related resources\n});\n```\n\n## Error Handling\n\nThe library provides typed error classes for different error scenarios:\n\n```typescript\nimport {\n  ITGlueClient,\n  ITGlueNotFoundError,\n  ITGlueValidationError,\n  ITGlueAuthenticationError,\n  ITGlueRateLimitError,\n} from 'node-it-glue';\n\ntry {\n  await client.organizations.get('12345');\n} catch (error) {\n  if (error instanceof ITGlueNotFoundError) {\n    console.error('Organization not found');\n  } else if (error instanceof ITGlueValidationError) {\n    console.error('Validation errors:', error.getErrorMessages());\n  } else if (error instanceof ITGlueAuthenticationError) {\n    console.error('Invalid API key');\n  } else if (error instanceof ITGlueRateLimitError) {\n    console.error('Rate limited, retry after:', error.retryAfter);\n  } else {\n    throw error;\n  }\n}\n```\n\n## Available Resources\n\n### Organizations\n\n```typescript\n// List\nconst { data, meta } = await client.organizations.list(params?);\n\n// List all (auto-paginate)\nfor await (const org of client.organizations.listAll(params?)) { }\n\n// Get\nconst org = await client.organizations.get(id, params?);\n\n// Create\nconst newOrg = await client.organizations.create(data);\n\n// Update\nconst updated = await client.organizations.update(id, data);\n\n// Delete\nawait client.organizations.delete(id);\n```\n\n### Organization Types\n\n```typescript\nconst { data } = await client.organizationTypes.list(params?);\nconst newType = await client.organizationTypes.create(data);\nconst updated = await client.organizationTypes.update(id, data);\n```\n\n### Organization Statuses\n\n```typescript\nconst { data } = await client.organizationStatuses.list(params?);\nconst newStatus = await client.organizationStatuses.create(data);\nconst updated = await client.organizationStatuses.update(id, data);\n```\n\n### Configurations\n\n```typescript\n// List all configurations\nconst { data } = await client.configurations.list();\n\n// List configurations for an organization\nconst { data } = await client.configurations.listByOrg(orgId);\n\n// Get with related data\nconst config = await client.configurations.get(id, {\n  include: 'configuration_interfaces,related_items',\n});\n\n// Create\nconst newConfig = await client.configurations.create({\n  organizationId: 123,\n  configurationTypeId: 1,\n  name: 'Server-01',\n});\n```\n\n### Configuration Types, Statuses, Interfaces\n\n```typescript\n// Configuration Types\nconst { data } = await client.configurationTypes.list();\nconst type = await client.configurationTypes.create({ name: 'Server' });\n\n// Configuration Statuses\nconst { data } = await client.configurationStatuses.list();\nconst status = await client.configurationStatuses.create({ name: 'Active' });\n\n// Configuration Interfaces (nested under configurations)\nconst { data } = await client.configurationInterfaces.listByConfig(configId);\nconst iface = await client.configurationInterfaces.create({\n  configurationId: 123,\n  name: 'eth0',\n  ipAddress: '192.168.1.1',\n});\n```\n\n### Contacts\n\n```typescript\n// List contacts\nconst { data } = await client.contacts.list();\n\n// List contacts for an organization\nconst { data } = await client.contacts.listByOrg(orgId);\n\n// Create a contact\nconst contact = await client.contacts.create({\n  organizationId: 123,\n  firstName: 'John',\n  lastName: 'Doe',\n  contactTypeId: 1,\n});\n```\n\n### Contact Types\n\n```typescript\nconst { data } = await client.contactTypes.list();\nconst type = await client.contactTypes.create({ name: 'Technical' });\n```\n\n### Documents\n\n```typescript\n// List documents\nconst { data } = await client.documents.list();\n\n// List documents for an organization\nconst { data } = await client.documents.listByOrg(orgId);\n\n// Create a document\nconst doc = await client.documents.create({\n  organizationId: 123,\n  name: 'Network Diagram',\n});\n\n// Publish a document\nawait client.documents.publish(docId);\n```\n\n### Document Sections and Images\n\n```typescript\n// Document Sections\nconst { data } = await client.documentSections.listByDoc(docId);\nconst section = await client.documentSections.create(docId, {\n  name: 'Overview',\n  content: '\u003cp\u003eIntroduction...\u003c/p\u003e',\n});\n\n// Document Images\nconst { data } = await client.documentImages.list();\nconst image = await client.documentImages.create({\n  documentId: 123,\n  content: base64ImageData,\n});\n```\n\n### Passwords\n\n```typescript\n// List passwords (values hidden by default)\nconst { data } = await client.passwords.list();\n\n// List passwords with values visible\nconst { data } = await client.passwords.list({ showPassword: true });\n\n// Get a password with value\nconst pwd = await client.passwords.get(id, { showPassword: true });\n\n// Create a password\nconst newPwd = await client.passwords.create({\n  organizationId: 123,\n  name: 'Admin Password',\n  password: 'secret123',\n  passwordCategoryId: 1,\n});\n```\n\n### Password Categories and Folders\n\n```typescript\n// Password Categories\nconst { data } = await client.passwordCategories.list();\nconst cat = await client.passwordCategories.create({ name: 'Server Credentials' });\n\n// Password Folders (nested under organizations)\nconst { data } = await client.passwordFolders.listByOrg(orgId);\nconst folder = await client.passwordFolders.create(orgId, { name: 'Production' });\n```\n\n### Flexible Assets\n\n```typescript\n// List flexible asset types\nconst { data: types } = await client.flexibleAssetTypes.list();\n\n// List flexible assets (requires filter)\nconst { data } = await client.flexibleAssets.list({\n  filter: { flexibleAssetTypeId: 123 },\n});\n\n// Create a flexible asset\nconst asset = await client.flexibleAssets.create({\n  organizationId: 123,\n  flexibleAssetTypeId: 456,\n  traits: {\n    'custom-field-1': 'value1',\n    'custom-field-2': 'value2',\n  },\n});\n```\n\n### Flexible Asset Types and Fields\n\n```typescript\n// Flexible Asset Types\nconst { data } = await client.flexibleAssetTypes.list();\nconst type = await client.flexibleAssetTypes.create({\n  name: 'Network Documentation',\n  icon: 'sitemap',\n});\n\n// Flexible Asset Fields (nested under types)\nconst { data } = await client.flexibleAssetFields.listByType(typeId);\nconst field = await client.flexibleAssetFields.create({\n  flexibleAssetTypeId: 123,\n  name: 'IP Range',\n  kind: 'Text',\n});\n```\n\n### Locations\n\n```typescript\n// List locations for an organization\nconst { data } = await client.locations.listByOrg(orgId);\n\n// Create a location\nconst loc = await client.locations.create({\n  organizationId: 123,\n  name: 'Main Office',\n  addressLine1: '123 Main St',\n  city: 'Springfield',\n  postalCode: '12345',\n  countryId: 1,\n  regionId: 1,\n});\n```\n\n### Users and Groups\n\n```typescript\n// Users (read-only creation, can update)\nconst { data } = await client.users.list();\nconst user = await client.users.get(userId);\nconst updated = await client.users.update(userId, { firstName: 'Jane' });\n\n// Bulk update users\nconst results = await client.users.bulkUpdate({\n  users: [\n    { id: 1, firstName: 'Jane' },\n    { id: 2, lastName: 'Smith' },\n  ],\n});\n\n// User Metrics\nconst { data } = await client.userMetrics.list({\n  filter: { userId: 123, date: '2024-01-01' },\n});\n\n// Groups\nconst { data } = await client.groups.list();\nconst group = await client.groups.create({ name: 'Admins' });\n```\n\n### Metadata Resources\n\n```typescript\n// Manufacturers\nconst { data } = await client.manufacturers.list();\nconst mfg = await client.manufacturers.create({ name: 'Dell' });\n\n// Models (nested under manufacturers)\nconst { data } = await client.models.listByManufacturer(mfgId);\nconst model = await client.models.create({ manufacturerId: 1, name: 'PowerEdge R640' });\n\n// Platforms (read-only)\nconst { data } = await client.platforms.list();\n\n// Operating Systems (read-only)\nconst { data } = await client.operatingSystems.list();\n\n// Countries (read-only)\nconst { data } = await client.countries.list();\nconst country = await client.countries.get(countryId);\n\n// Regions (nested under countries, read-only)\nconst { data } = await client.regions.listByCountry(countryId);\n```\n\n### Miscellaneous Resources\n\n```typescript\n// Domains (nested under organizations, read-only)\nconst { data } = await client.domains.listByOrg(orgId);\n\n// Expirations (read-only)\nconst { data } = await client.expirations.list();\nconst exp = await client.expirations.get(expId);\n\n// Logs (read-only)\nconst { data } = await client.logs.list();\nfor await (const log of client.logs.listAll()) {\n  console.log(log.action);\n}\n\n// Attachments (nested under various resources)\nconst { data } = await client.attachments.list('configurations', configId);\nconst att = await client.attachments.create('configurations', configId, {\n  name: 'diagram.png',\n  content: base64Data,\n});\nawait client.attachments.delete('configurations', configId, attachmentId);\n\n// Related Items\nawait client.relatedItems.create('configurations', configId, {\n  destinationType: 'passwords',\n  destinationId: passwordId,\n});\nawait client.relatedItems.delete('configurations', configId, relatedItemId);\n\n// Exports\nconst exportJob = await client.exports.create({\n  organizationIds: [123, 456],\n  includePasswords: true,\n});\nconst status = await client.exports.get(exportJob.id);\n\n// Checklists (nested under organizations)\nconst { data } = await client.checklists.listByOrg(orgId);\nconst checklist = await client.checklists.get(checklistId);\nconst updated = await client.checklists.update(checklistId, { completed: true });\n```\n\n## Complete Resource Reference\n\n| Resource | Methods |\n|----------|---------|\n| `organizations` | list, listAll, get, create, update, delete |\n| `organizationTypes` | list, listAll, get, create, update |\n| `organizationStatuses` | list, listAll, get, create, update |\n| `configurations` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete |\n| `configurationTypes` | list, listAll, get, create, update, delete |\n| `configurationStatuses` | list, listAll, get, create, update, delete |\n| `configurationInterfaces` | listByConfig, create, update, delete |\n| `contacts` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete |\n| `contactTypes` | list, listAll, get, create, update |\n| `documents` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete, publish |\n| `documentSections` | listByDoc, create, update, delete |\n| `documentImages` | list, create, delete |\n| `passwords` | list, listAll, listByOrg, listAllByOrg, get, create, update, delete |\n| `passwordCategories` | list, listAll, get, create, update, delete |\n| `passwordFolders` | listByOrg, create, update, delete |\n| `flexibleAssetTypes` | list, listAll, get, create, update, delete |\n| `flexibleAssetFields` | listByType, create, update, delete |\n| `flexibleAssets` | list, listAll, get, create, update, delete |\n| `locations` | listByOrg, create, update, delete |\n| `users` | list, listAll, get, update, bulkUpdate |\n| `userMetrics` | list, listAll |\n| `groups` | list, listAll, get, create, update, delete |\n| `manufacturers` | list, listAll, get, create, update |\n| `models` | listByManufacturer, create, update |\n| `platforms` | list |\n| `operatingSystems` | list |\n| `countries` | list, listAll, get |\n| `regions` | listByCountry |\n| `domains` | listByOrg |\n| `expirations` | list, listAll, get |\n| `logs` | list, listAll |\n| `attachments` | list, create, update, delete |\n| `relatedItems` | create, update, delete |\n| `exports` | list, listAll, get, create, delete |\n| `checklists` | listByOrg, get, update, delete |\n\n## Rate Limiting\n\nThe library automatically handles IT Glue's rate limits (3000 requests per 5 minutes):\n\n- **Request tracking** - Counts requests within the rolling window\n- **Preemptive throttling** - Slows down when approaching the limit (default: 80%)\n- **429 handling** - Automatically retries with exponential backoff\n- **Configurable** - Adjust thresholds or disable entirely\n\nMonitor rate limit status:\n\n```typescript\nconst status = client.getRateLimitStatus();\nconsole.log(`Requests: ${status.currentCount}/${status.maxRequests}`);\nconsole.log(`Remaining: ${status.remaining}`);\nconsole.log(`Is throttling: ${status.isThrottling}`);\n```\n\n## JSON:API Handling\n\nIT Glue uses the JSON:API specification. This library transparently handles:\n\n- **Deserialization** - Flattens `attributes` and converts kebab-case to camelCase\n- **Serialization** - Wraps data in JSON:API envelope for POST/PATCH requests\n- **Relationships** - Preserves relationship links in a normalized format\n- **Pagination meta** - Converts pagination info to camelCase\n\nRaw API response:\n```json\n{\n  \"data\": {\n    \"id\": \"123\",\n    \"type\": \"organizations\",\n    \"attributes\": {\n      \"name\": \"Acme Corp\",\n      \"organization-type-name\": \"Customer\",\n      \"created-at\": \"2024-01-15T10:30:00.000Z\"\n    }\n  }\n}\n```\n\nDeserialized client response:\n```typescript\n{\n  id: '123',\n  type: 'organizations',\n  name: 'Acme Corp',\n  organizationTypeName: 'Customer',\n  createdAt: '2024-01-15T10:30:00.000Z'\n}\n```\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Type checking\nnpm run typecheck\n\n# Build\nnpm run build\n```\n\n## License\n\nApache-2.0\n\n## Contributing\n\nContributions are welcome! Please read our contributing guidelines before submitting a pull request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwyre-technology%2Fnode-it-glue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwyre-technology%2Fnode-it-glue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwyre-technology%2Fnode-it-glue/lists"}