From bc384e5c3ee917289e6e826743db35330b85c677 Mon Sep 17 00:00:00 2001 From: Aaron de Mello Date: Wed, 18 Jun 2025 10:33:41 -0400 Subject: [PATCH 1/2] feat: add support for includeHiddenFolders query parameter in folders list endpoint --- CHANGELOG.md | 1 + examples/folders/README.md | 61 +++++++++++++++++++++++ examples/folders/folders.ts | 88 +++++++++++++++++++++++++++++++++ src/models/folders.ts | 4 ++ tests/resources/folders.spec.ts | 58 +++++++++++++++++++++- 5 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 examples/folders/README.md create mode 100644 examples/folders/folders.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index df9c6477..291e0d4e 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 ### Fixed - Fixed 3MB payload size limit to consider total request size (message body + attachments) instead of just attachment size when determining whether to use multipart/form-data encoding diff --git a/examples/folders/README.md b/examples/folders/README.md new file mode 100644 index 00000000..945f119b --- /dev/null +++ b/examples/folders/README.md @@ -0,0 +1,61 @@ +# 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 \ No newline at end of file diff --git a/examples/folders/folders.ts b/examples/folders/folders.ts new file mode 100644 index 00000000..8af93308 --- /dev/null +++ b/examples/folders/folders.ts @@ -0,0 +1,88 @@ +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); +} \ No newline at end of file diff --git a/src/models/folders.ts b/src/models/folders.ts index 87ccfe92..436be8f0 100644 --- a/src/models/folders.ts +++ b/src/models/folders.ts @@ -101,6 +101,10 @@ export interface ListFolderQueryParams extends ListQueryParams { * (Microsoft and EWS only.) Use the ID of a folder to find all child folders it contains. */ parentId?: string; + /** + * (Microsoft only) When true, Nylas includes hidden folders in its response. + */ + includeHiddenFolders?: boolean; } export type UpdateFolderRequest = Partial; diff --git a/tests/resources/folders.spec.ts b/tests/resources/folders.spec.ts index ae84a390..3cad179b 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', () => { @@ -73,6 +73,62 @@ describe('Folders', () => { }, }); }); + + it('should call apiClient.request with include_hidden_folders query parameter', async () => { + await folders.list({ + identifier: 'id123', + queryParams: { + includeHiddenFolders: true, + }, + overrides: { + apiUri: 'https://test.api.nylas.com', + headers: { override: 'bar' }, + }, + }); + + expect(apiClient.request).toHaveBeenCalledWith({ + method: 'GET', + path: '/v3/grants/id123/folders', + queryParams: { + includeHiddenFolders: true, + }, + overrides: { + apiUri: 'https://test.api.nylas.com', + headers: { override: 'bar' }, + }, + }); + }); + + 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', + }, + 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', + }, + overrides: { + apiUri: 'https://test.api.nylas.com', + headers: { override: 'bar' }, + }, + }); + }); }); describe('find', () => { From c80fe5f37840e6c94e4214be5a7cdf405fad84a5 Mon Sep 17 00:00:00 2001 From: Aaron de Mello Date: Fri, 20 Jun 2025 08:05:47 -0400 Subject: [PATCH 2/2] prettier fix --- src/models/folders.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/folders.ts b/src/models/folders.ts index e594b9f1..58784e21 100644 --- a/src/models/folders.ts +++ b/src/models/folders.ts @@ -101,7 +101,7 @@ export interface ListFolderQueryParams extends ListQueryParams { * (Microsoft and EWS only.) Use the ID of a folder to find all child folders it contains. */ parentId?: string; - + /** * (Microsoft only) When true, Nylas includes hidden folders in its response. */