import { ITGlueClient } from '../client'; import { QueryUtilOptions, QueryParams, RequestBody, BaseListResponse, BaseItemResponse, DocumentResource } from '../types'; /** * Documents resource module for IT Glue API * * Provides methods to interact with the /documents endpoint. * Documents represent various types of documentation stored in IT Glue, including * policies, procedures, runbooks, technical documentation, and other important * organizational knowledge. Documents can contain sensitive information and support * rich text formatting, attachments, and organizational relationships. * * **Security Note:** Documents may contain sensitive organizational information. * Ensure proper access controls are in place and handle document data according * to your organization's data classification and security policies. * * ## Related Resources * Documents are commonly used with: * - {@link Organizations} - Parent organizations that own documents * - {@link DocumentCategories} - Classify documents by type (policy, procedure, manual) * - {@link Attachments} - Files and media attached to documents * - {@link Contacts} - People who create, own, or are responsible for documents * - {@link Configurations} - IT assets that documents describe or relate to * - {@link Passwords} - Credentials documented in security procedures * - {@link FlexibleAssets} - Custom documentation and knowledge management * - {@link RelatedItems} - Create relationships between documents and other resources * - {@link Tags} - Categorize and label documents for better organization * - {@link Locations} - Physical sites that documents relate to * * @see {@link Organizations#list} for retrieving documents by organization * @see {@link Documents#list} for retrieving available document categories * @see {@link Attachments#list} for retrieving attachments associated with documents * @see {@link Contacts#list} for retrieving contacts associated with documents * * @example * import { ITGlueClient } from '../client'; * import { Documents } from './resources/documents'; * * const client = new ITGlueClient({ apiKey: 'your-api-key' }); * const documents = new Documents(client); * * // List documents * const list = await documents.list(); * * // Get a single document * const doc = await documents.get('123'); * * // Create a document * const created = await documents.create({ * data: { * type: 'documents', * attributes: { * name: 'Server Maintenance Procedure', * body: 'Detailed maintenance steps...' * } * } * }); * * // Update a document * const updated = await documents.update('123', { * data: { * type: 'documents', * attributes: { * name: 'Updated Server Maintenance Procedure' * } * } * }); * * // Delete a document * await documents.delete('123'); * * @category Documents & Attachments */ export declare class Documents { private client; private basePath; private paginationUtil; /** * Create a Documents resource instance * @param {ITGlueClient} client - ITGlueClient instance */ constructor(client: ITGlueClient); /** * List all documents * @param {QueryUtilOptions} [options] - Optional query parameters (filter, sort, page, etc.) * @param {boolean} [allPages=false] - If true, fetches all pages automatically * @returns {Promise>} List of documents and pagination metadata * @example * // Basic usage - get first page of documents * const results = await client.documents.list(); * console.log(`Found ${results.data.length} documents`); * console.log('Total pages:', results.meta.pagination.total_pages); * * @example * // Advanced usage with pagination and sorting * const results = await client.documents.list({ * page: { number: 2, size: 50 }, * sort: '-updated_at', // Sort by most recently updated * include: ['organization', 'attachments', 'created_by'] // Include related data * }); * * @example * // Filtering documents by organization and category * const orgDocs = await client.documents.list({ * organization_id: '123', * filter: { name: 'Policy' }, * sort: 'name' * }); * * console.log('Organization policy documents:'); * orgDocs.data.forEach(doc => { * console.log(`- ${doc.attributes.name} (${doc.attributes.restricted ? 'Restricted' : 'Public'})`); * }); * * @example * // Get all documents with categorization analysis * const allDocs = await client.documents.list({}, true); // allPages = true * * // Categorize documents by type and access level * const analysis = { * totalDocs: allDocs.data.length, * categories: {}, * accessLevels: { restricted: 0, public: 0 }, * recentUpdates: [], * largeDocuments: [] * }; * * const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); * * allDocs.data.forEach(doc => { * // Categorize by document type (based on name patterns) * const name = doc.attributes.name.toLowerCase(); * let category = 'other'; * if (name.includes('policy')) category = 'policies'; * else if (name.includes('procedure') || name.includes('runbook')) category = 'procedures'; * else if (name.includes('manual') || name.includes('guide')) category = 'documentation'; * else if (name.includes('contract') || name.includes('agreement')) category = 'contracts'; * * analysis.categories[category] = (analysis.categories[category] || 0) + 1; * * // Track access levels * if (doc.attributes.restricted) { * analysis.accessLevels.restricted++; * } else { * analysis.accessLevels.public++; * } * * // Track recent updates * if (new Date(doc.attributes.updated_at) > oneWeekAgo) { * analysis.recentUpdates.push({ * name: doc.attributes.name, * updated: doc.attributes.updated_at, * id: doc.id * }); * } * * // Track large documents (>50KB body content) * if (doc.attributes.body && doc.attributes.body.length > 50000) { * analysis.largeDocuments.push({ * name: doc.attributes.name, * size: doc.attributes.body.length, * id: doc.id * }); * } * }); * * console.log('Document analysis:', analysis); * * @example * // Manual pagination for large document libraries * async function getAllDocuments(filterParams = {}) { * let page = 1; * let allResults = []; * let hasMore = true; * * while (hasMore) { * const response = await client.documents.list({ * ...filterParams, * page: { number: page, size: 100 }, * sort: 'created_at' * }); * * allResults = [...allResults, ...response.data]; * hasMore = response.meta.pagination.total_pages > page; * page++; * } * * return allResults; * } * * @example * // Error handling for list operations * try { * const results = await client.documents.list({ * organization_id: 'invalid-id' * }); * } catch (error) { * if (error.response?.status === 400) { * console.log('Invalid filter parameters:', error.response.data.errors); * } else if (error.response?.status === 401) { * console.log('Authentication failed - check your API key'); * } else if (error.response?.status === 403) { * console.log('Access denied - insufficient permissions to view documents'); * } else { * console.log('Request failed:', error.message); * } * } */ list(options?: QueryUtilOptions, allPages?: boolean): Promise>; /** * Get a single document by ID * @param {string} id - Document ID * @param {QueryParams} [params] - Optional query parameters * @returns {Promise>} Document resource * @example * // Basic usage - get document by ID * const document = await client.documents.get('123'); * console.log('Document name:', document.data.attributes.name); * console.log('Content length:', document.data.attributes.body?.length || 0); * console.log('Restricted:', document.data.attributes.restricted); * * @example * // Get document with related data included * const documentWithDetails = await client.documents.get('123', { * include: ['organization', 'attachments', 'created_by'] * }); * * // Access included data * const included = documentWithDetails.included || []; * const organization = included.find(item => item.type === 'organizations'); * const attachments = included.filter(item => item.type === 'attachments'); * const creator = included.find(item => item.type === 'users'); * * console.log('Organization:', organization?.attributes?.name); * console.log('Attachments:', attachments.length); * console.log('Created by:', creator?.attributes?.name); * * @example * // Detailed document analysis and content processing * const document = await client.documents.get('123'); * const attrs = document.data.attributes; * * const docInfo = { * name: attrs.name, * contentLength: attrs.body?.length || 0, * wordCount: attrs.body ? attrs.body.replace(/<[^>]*>/g, '').split(/\s+/).length : 0, * isRestricted: attrs.restricted, * folder: attrs.folder_id, * created: attrs.created_at, * lastModified: attrs.updated_at, * notes: attrs.notes || 'No notes', * hasRichContent: attrs.body?.includes('<') || false * }; * * // Extract headings from HTML content * if (attrs.body) { * const headingMatches = attrs.body.match(/]*>(.*?)<\/h[1-6]>/gi); * docInfo.headings = headingMatches ? * headingMatches.map(h => h.replace(/<[^>]*>/g, '').trim()) : []; * } * * console.log('Document analysis:', docInfo); * * @example * // Error handling for get operations * try { * const document = await client.documents.get('invalid-id'); * } catch (error) { * if (error.response?.status === 404) { * console.log('Document not found'); * } else if (error.response?.status === 403) { * console.log('Access denied - insufficient permissions or restricted document'); * } else { * console.log('Error retrieving document:', error.message); * } * } * * @example * // Safe get with existence check and content validation * async function safeGetDocument(id) { * try { * const document = await client.documents.get(id); * * // Validate document content * const attrs = document.data.attributes; * if (!attrs.name || attrs.name.trim() === '') { * console.warn('Document has empty name'); * } * * if (!attrs.body || attrs.body.trim() === '') { * console.warn('Document has no content'); * } * * return document.data; * } catch (error) { * if (error.response?.status === 404) { * return null; // Document doesn't exist * } * throw error; // Re-throw other errors * } * } * @see * {@link Organizations#get} - Get specific organization details * {@link Organizations#list} - List organizations related to documents * {@link Attachments#get} - Get specific attachment details * {@link Attachments#list} - List attachments related to documents */ get(id: string, params?: QueryParams): Promise>; /** * Create a new document * * Creates a new document in IT Glue. Documents can contain rich text content, * be associated with organizations, and have various access control settings. * Consider data classification when creating documents with sensitive content. * * @param {RequestBody} data - Document data (JSON:API format) * @returns {Promise>} Created document resource * @throws {Error} When validation fails (422) or unauthorized (401) * @example * // Basic document creation with required fields * const created = await client.documents.create({ * data: { * type: 'documents', * attributes: { * name: 'Server Maintenance Procedure', * body: '

Maintenance Steps

1. Check system status...

', * folder_id: '456' * }, * relationships: { * organization: { * data: { type: 'organizations', id: '123' } * } * } * } * }); * * console.log('Created document with ID:', created.data.id); * * @example * // Advanced document creation with rich content and security settings * const created = await client.documents.create({ * data: { * type: 'documents', * attributes: { * name: 'Information Security Policy', * body: ` *

Information Security Policy

*

Purpose

*

This document outlines our organization's approach to information security...

*

Scope

*
    *
  • All employees and contractors
  • *
  • All IT systems and data
  • *
  • Physical and digital assets
  • *
*

Policy Details

*

Detailed security requirements and procedures...

* `, * restricted: true, * folder_id: '456', * notes: 'Confidential - HR and IT management only. Review annually.' * }, * relationships: { * organization: { * data: { type: 'organizations', id: '123' } * } * } * } * }); * * @example * // Bulk document creation with error handling * async function createMultipleDocuments(documents) { * const results = []; * * for (const docData of documents) { * try { * const created = await client.documents.create({ * data: { * type: 'documents', * attributes: docData.attributes, * relationships: docData.relationships * } * }); * results.push({ status: 'created', id: created.data.id, name: docData.attributes.name }); * } catch (error) { * results.push({ * status: 'error', * name: docData.attributes.name, * error: error.response?.status === 422 ? 'validation_failed' : error.message * }); * } * } * * return results; * } * * @example * // Error handling for document creation * try { * const created = await client.documents.create({ * data: { * type: 'documents', * attributes: { * name: '', // Invalid empty name * body: 'Content without name' * } * } * }); * } catch (error) { * if (error.response?.status === 422) { * console.log('Validation failed:', error.response.data.errors); * } else if (error.response?.status === 401) { * console.log('Authentication failed - check your API key'); * } else if (error.response?.status === 403) { * console.log('Permission denied - insufficient rights to create documents'); * } else { * console.log('Creation failed:', error.message); * } * } * @see * {@link Organizations#create} - Create new organization * {@link Organizations#list} - List organizations related to documents * {@link Attachments#create} - Create new attachment * {@link Attachments#list} - List attachments related to documents */ create(data: RequestBody): Promise>; /** * Update a document by ID * * Updates an existing document. Changes to document content, access restrictions, * or organizational associations will be reflected immediately. Consider version * control and change tracking for important documents. * * @param {string} id - Document ID * @param {RequestBody} data - Updated document data (JSON:API format) * @returns {Promise>} Updated document resource * @throws {Error} When document not found (404) or validation fails (422) * @example * // Basic update - modify document content and metadata * const updated = await client.documents.update('123', { * data: { * type: 'documents', * attributes: { * name: 'Updated Server Maintenance Procedure', * body: '

Revised Maintenance Steps

1. Updated check procedures...

', * notes: 'Updated with latest best practices' * } * } * }); * * console.log('Updated document:', updated.data.attributes.name); * * @example * // Update document access settings and security classification * const updated = await client.documents.update('123', { * data: { * type: 'documents', * attributes: { * restricted: false, * notes: 'Made public for all team members after security review' * } * } * }); * * @example * // Conditional update based on current document state * async function conditionalUpdateDocument(id, updates) { * try { * // First, get current state * const current = await client.documents.get(id); * * // Check if update is needed * const currentAttrs = current.data.attributes; * const needsUpdate = Object.keys(updates.attributes || {}).some( * key => currentAttrs[key] !== updates.attributes[key] * ); * * if (!needsUpdate) { * console.log('Document is already up to date'); * return current; * } * * // Add timestamp to notes if updating content * if (updates.attributes.body) { * const timestamp = new Date().toISOString(); * updates.attributes.notes = `${updates.attributes.notes || ''} [Updated: ${timestamp}]`.trim(); * } * * // Perform update * return await client.documents.update(id, { * data: { * type: 'documents', * attributes: updates.attributes * } * }); * } catch (error) { * console.error('Update failed:', error.message); * throw error; * } * } * * @example * // Error handling for document updates * try { * const updated = await client.documents.update('123', { * data: { * type: 'documents', * attributes: { * name: 'Updated Document', * body: '

New Content

' * } * } * }); * } catch (error) { * if (error.response?.status === 404) { * console.log('Document not found'); * } else if (error.response?.status === 422) { * console.log('Validation failed:', error.response.data.errors); * } else if (error.response?.status === 403) { * console.log('Permission denied - cannot update document'); * } else { * console.log('Update failed:', error.message); * } * } * @see * {@link Organizations#update} - Update organization * {@link Organizations#get} - Get specific organization details * {@link Attachments#update} - Update attachment * {@link Attachments#get} - Get specific attachment details */ update(id: string, data: RequestBody): Promise>; /** * Delete a document by ID * * Permanently deletes a document from IT Glue. This action cannot be undone. * Consider archiving or moving documents to a different folder instead of * deletion for important organizational knowledge. * * @param {string} id - Document ID * @returns {Promise} * @throws {Error} When document not found (404) or deletion not allowed (403) * @example * // Basic deletion * await client.documents.delete('123'); * console.log('Document deleted successfully'); * * @example * // Safe deletion with confirmation and backup * async function safeDeleteDocument(id) { * try { * // First verify the document exists and get its content * const document = await client.documents.get(id); * console.log(`Deleting document: ${document.data.attributes.name}`); * * // Optional: Create backup or log deletion * const backup = { * id: document.data.id, * name: document.data.attributes.name, * body: document.data.attributes.body, * deletedAt: new Date().toISOString() * }; * console.log('Document backup created:', backup.name); * * // Perform deletion * await client.documents.delete(id); * console.log('Document deleted successfully'); * return true; * } catch (error) { * if (error.response?.status === 404) { * console.log('Document not found - may already be deleted'); * return false; * } * throw error; * } * } * * @example * // Bulk deletion with error handling * async function deleteMultipleDocuments(ids) { * const results = []; * * for (const id of ids) { * try { * await client.documents.delete(id); * results.push({ id, status: 'deleted' }); * } catch (error) { * results.push({ * id, * status: 'error', * error: error.response?.status === 404 ? 'not_found' : error.message * }); * } * } * * return results; * } * * @example * // Error handling for document deletion * try { * await client.documents.delete('123'); * } catch (error) { * if (error.response?.status === 403) { * console.log('Insufficient permissions to delete document'); * } else if (error.response?.status === 404) { * console.log('Document not found - may already be deleted'); * } else if (error.response?.status === 409) { * console.log('Cannot delete - document may be referenced by other resources'); * } else { * console.log('Deletion failed:', error.message); * } * } * @see * {@link Organizations#list} - List organizations related to documents * {@link Organizations#get} - Get specific organization details * {@link Attachments#list} - List attachments related to documents * {@link Attachments#get} - Get specific attachment details */ delete(id: string): Promise; }