diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e9fce71..57682475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for `trackingOptions` property in Message responses when using `fields=include_tracking_options` - Support for `rawMime` property in Message responses when using `fields=raw_mime` - `MessageTrackingOptions` interface for tracking message opens, thread replies, link clicks, and custom labels +- Support for `includeHiddenFolders` query parameter in folders list endpoint for Microsoft accounts - Support for `singleLevel` query parameter in `ListFolderQueryParams` for Microsoft accounts to control folder hierarchy traversal ### Fixed diff --git a/examples/folders/README.md b/examples/folders/README.md index 6a45c8cb..240293a5 100644 --- a/examples/folders/README.md +++ b/examples/folders/README.md @@ -1,3 +1,65 @@ +# Folders Example + +This example demonstrates how to use the Nylas Node.js SDK to work with folders. + +## Features Demonstrated + +- List all folders for a grant +- Use the `includeHiddenFolders` parameter (Microsoft only) to include hidden folders in the response +- Filter folders by parent/child relationship +- Display folder attributes and metadata + +## Setup + +1. Copy `.env.example` to `.env` in the examples directory +2. Add your Nylas API credentials and grant ID: + ``` + NYLAS_API_KEY=your_api_key_here + NYLAS_GRANT_ID=your_grant_id_here + NYLAS_API_URI=https://api.us.nylas.com # or your specific Nylas region + ``` + +## Running the Example + +```bash +npm install +npm run folders +``` + +Or run directly with ts-node: +```bash +npx ts-node folders.ts +``` + +## Microsoft-Specific Features + +The `includeHiddenFolders` parameter is specific to Microsoft accounts: + +```typescript +const foldersWithHidden = await nylas.folders.list({ + identifier: GRANT_ID, + queryParams: { + includeHiddenFolders: true, // Microsoft only - includes hidden folders + }, +}); +``` + +This parameter defaults to `false` and when set to `true`, includes folders that are typically hidden from the user interface, such as system folders used by Microsoft Exchange for internal operations. + +## Expected Output + +The example will output: +1. A list of all visible folders +2. A list of all folders including hidden ones (if using a Microsoft account) +3. A filtered list showing only parent folders with their metadata + +## Error Handling + +The example includes proper error handling and will display helpful error messages if: +- Environment variables are not set +- API requests fail +- Authentication issues occur +======= # Nylas Folders API Examples This directory contains examples of how to use the Nylas Folders API with the Nylas Node.js SDK, including the new `singleLevel` query parameter. @@ -111,4 +173,4 @@ const allFolders = await nylas.folders.list({ ## Documentation -For more information, see the [Nylas API Documentation](https://developer.nylas.com/). \ No newline at end of file +For more information, see the [Nylas API Documentation](https://developer.nylas.com/). diff --git a/examples/folders/folders.ts b/examples/folders/folders.ts index 7085b366..4e006f0b 100644 --- a/examples/folders/folders.ts +++ b/examples/folders/folders.ts @@ -1,3 +1,92 @@ +import 'dotenv/config'; + +import Nylas from '../../src/nylas'; + +const GRANT_ID = process.env.NYLAS_GRANT_ID || ''; + +const nylas = new Nylas({ + apiKey: process.env.NYLAS_API_KEY || '', + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', +}); + +/** + * This example shows how to list folders using the Nylas Node.js SDK. + * + * For Microsoft accounts, you can use the includeHiddenFolders parameter + * to include hidden folders in the response. + */ +async function listFolders() { + try { + console.log('Listing all folders...\n'); + + // List all folders + const folders = await nylas.folders.list({ + identifier: GRANT_ID, + }); + + console.log('Found', folders.data.length, 'folders'); + + folders.data.forEach((folder, index) => { + console.log(`${index + 1}. ${folder.name} (ID: ${folder.id})`); + if (folder.parentId) { + console.log(` Parent ID: ${folder.parentId}`); + } + if (folder.attributes && folder.attributes.length > 0) { + console.log(` Attributes: ${folder.attributes.join(', ')}`); + } + console.log(''); + }); + + // For Microsoft accounts: List folders including hidden ones + console.log('\n--- Microsoft Only: Including Hidden Folders ---\n'); + + const foldersWithHidden = await nylas.folders.list({ + identifier: GRANT_ID, + queryParams: { + includeHiddenFolders: true, + }, + }); + + console.log('Found', foldersWithHidden.data.length, 'folders (including hidden)'); + + // List only parent folders (no parentId) + console.log('\n--- Parent Folders Only ---\n'); + + const parentFoldersWithHidden = await nylas.folders.list({ + identifier: GRANT_ID, + queryParams: { + includeHiddenFolders: true, + }, + }); + + const parentFolders = parentFoldersWithHidden.data.filter(folder => !folder.parentId); + console.log('Found', parentFolders.length, 'parent folders'); + + parentFolders.forEach((folder, index) => { + console.log(`${index + 1}. ${folder.name} (ID: ${folder.id})`); + if (folder.childCount) { + console.log(` Child folders: ${folder.childCount}`); + } + if (folder.totalCount) { + console.log(` Total items: ${folder.totalCount}`); + } + if (folder.unreadCount) { + console.log(` Unread items: ${folder.unreadCount}`); + } + console.log(''); + }); + + } catch (error) { + console.error('Error listing folders:', error); + } +} + +if (!GRANT_ID) { + console.error('Please set NYLAS_GRANT_ID in your environment variables'); +} else { + listFolders().catch(console.error); +} +======= import dotenv from 'dotenv'; import path from 'path'; import * as process from 'process'; @@ -215,4 +304,4 @@ if (require.main === module) { main().catch(console.error); } -export default main; \ No newline at end of file +export default main; diff --git a/src/models/folders.ts b/src/models/folders.ts index c3e33ffb..58784e21 100644 --- a/src/models/folders.ts +++ b/src/models/folders.ts @@ -102,6 +102,11 @@ export interface ListFolderQueryParams extends ListQueryParams { */ parentId?: string; + /** + * (Microsoft only) When true, Nylas includes hidden folders in its response. + */ + includeHiddenFolders?: boolean; + /** * (Microsoft only) If true, retrieves folders from a single-level hierarchy only. * If false, retrieves folders across a multi-level hierarchy. diff --git a/tests/resources/folders.spec.ts b/tests/resources/folders.spec.ts index 57a36dc0..d9be0728 100644 --- a/tests/resources/folders.spec.ts +++ b/tests/resources/folders.spec.ts @@ -16,7 +16,7 @@ describe('Folders', () => { }) as jest.Mocked; folders = new Folders(apiClient); - apiClient.request.mockResolvedValue({}); + apiClient.request.mockResolvedValue({ data: [] }); }); describe('deserializing', () => { @@ -78,6 +78,7 @@ describe('Folders', () => { await folders.list({ identifier: 'id123', queryParams: { + includeHiddenFolders: true, singleLevel: true, parentId: 'parent123', }, @@ -91,6 +92,7 @@ describe('Folders', () => { method: 'GET', path: '/v3/grants/id123/folders', queryParams: { + includeHiddenFolders: true, singleLevel: true, parentId: 'parent123', }, @@ -101,20 +103,36 @@ describe('Folders', () => { }); }); - it('should call apiClient.request with single_level set to false', async () => { + it('should call apiClient.request with all supported query parameters', async () => { await folders.list({ identifier: 'id123', queryParams: { + parentId: 'parent123', + includeHiddenFolders: false, + limit: 10, + pageToken: 'token123', singleLevel: false, }, + overrides: { + apiUri: 'https://test.api.nylas.com', + headers: { override: 'bar' }, + }, }); expect(apiClient.request).toHaveBeenCalledWith({ method: 'GET', path: '/v3/grants/id123/folders', queryParams: { + parentId: 'parent123', + includeHiddenFolders: false, + limit: 10, + pageToken: 'token123', singleLevel: false, }, + overrides: { + apiUri: 'https://test.api.nylas.com', + headers: { override: 'bar' }, + }, }); }); });