diff --git a/.prettierignore b/.prettierignore index 1e133a5a..7b52c4b2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,3 @@ node_modules lib -examples docs \ No newline at end of file diff --git a/examples/calendars/event_with_notetaker.ts b/examples/calendars/event_with_notetaker.ts index 43c807db..efeb2b7a 100644 --- a/examples/calendars/event_with_notetaker.ts +++ b/examples/calendars/event_with_notetaker.ts @@ -2,14 +2,14 @@ import dotenv from 'dotenv'; import path from 'path'; import * as process from 'process'; import Nylas from 'nylas'; -import { +import { Notetaker, Event, NylasResponse, NylasApiError, CreateEventRequest, UpdateEventRequest, - NotetakerSettings + NotetakerSettings, } from 'nylas'; // Load environment variables from .env file @@ -33,7 +33,7 @@ if (!calendarId) { // Initialize the Nylas client const nylas = new Nylas({ apiKey, - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); /** @@ -42,61 +42,63 @@ const nylas = new Nylas({ */ async function createEventWithNotetaker(): Promise> { console.log('\n=== Creating Event with Notetaker ==='); - + try { // Calculate start and end times (1 day from now, 1 hour duration) const startTime = Math.floor(Date.now() / 1000) + 24 * 60 * 60; // 24 hours from now const endTime = startTime + 60 * 60; // 1 hour later - + // Create the request body const requestBody: CreateEventRequest = { - title: "Project Planning Meeting", - description: "Initial project planning and resource allocation", + title: 'Project Planning Meeting', + description: 'Initial project planning and resource allocation', when: { startTime, - endTime + endTime, }, metadata: { - project_id: "PROJ-123", - priority: "high" + project_id: 'PROJ-123', + priority: 'high', }, conferencing: { - provider: "Google Meet", - autocreate: {} + provider: 'Google Meet', + autocreate: {}, }, notetaker: { - name: "Nylas Notetaker", + name: 'Nylas Notetaker', meetingSettings: { videoRecording: true, audioRecording: true, - transcription: true - } - } + transcription: true, + }, + }, }; - + console.log(`Request body: ${JSON.stringify(requestBody, null, 2)}`); - + // Create the event const event = await nylas.events.create({ identifier: grantId, requestBody, queryParams: { - calendarId - } + calendarId, + }, }); - + console.log(`Created event with ID: ${event.data.id}`); if (event.data.notetaker) { console.log(`Event Notetaker ID: ${event.data.notetaker.id}`); } - + return event; } catch (error) { if (error instanceof NylasApiError) { console.error(`Error creating event: ${error.message}`); console.error(`Error details: ${JSON.stringify(error, null, 2)}`); } else if (error instanceof Error) { - console.error(`Unexpected error in createEventWithNotetaker: ${error.message}`); + console.error( + `Unexpected error in createEventWithNotetaker: ${error.message}` + ); console.error(`Error type: ${error.constructor.name}`); } throw error; @@ -108,39 +110,47 @@ async function createEventWithNotetaker(): Promise> { * @param eventId The ID of the event to retrieve the Notetaker for * @returns The Notetaker associated with the event, or null if none found */ -async function getEventNotetaker(eventId: string): Promise | null> { +async function getEventNotetaker( + eventId: string +): Promise | null> { console.log('\n=== Retrieving Event Notetaker ==='); - + try { // First, retrieve the event to get the Notetaker ID const event = await nylas.events.find({ identifier: grantId, eventId, queryParams: { - calendarId - } + calendarId, + }, }); - + if (!event.data.notetaker || !event.data.notetaker.id) { console.log(`No Notetaker found for event ${eventId}`); return null; } - + // Get the Notetaker details const notetaker = await nylas.notetakers.find({ identifier: grantId, - notetakerId: event.data.notetaker.id + notetakerId: event.data.notetaker.id, }); - + console.log(`Found Notetaker for event ${eventId}:`); console.log(`- ID: ${notetaker.data.id}`); console.log(`- State: ${notetaker.data.state}`); console.log(`- Meeting Provider: ${notetaker.data.meetingProvider}`); console.log(`- Meeting Settings:`); - console.log(` - Video Recording: ${notetaker.data.meetingSettings.videoRecording}`); - console.log(` - Audio Recording: ${notetaker.data.meetingSettings.audioRecording}`); - console.log(` - Transcription: ${notetaker.data.meetingSettings.transcription}`); - + console.log( + ` - Video Recording: ${notetaker.data.meetingSettings.videoRecording}` + ); + console.log( + ` - Audio Recording: ${notetaker.data.meetingSettings.audioRecording}` + ); + console.log( + ` - Transcription: ${notetaker.data.meetingSettings.transcription}` + ); + return notetaker; } catch (error) { if (error instanceof NylasApiError) { @@ -160,53 +170,60 @@ async function getEventNotetaker(eventId: string): Promise> { +async function updateEventAndNotetaker( + eventId: string, + notetakerId: string +): Promise> { console.log('\n=== Updating Event and Notetaker ==='); - + try { // Create the request body with updated event details and Notetaker settings const requestBody: UpdateEventRequest = { - title: "Updated Project Planning Meeting", - description: "Revised project planning with new timeline", + title: 'Updated Project Planning Meeting', + description: 'Revised project planning with new timeline', metadata: { - project_id: "PROJ-123", - priority: "urgent" + project_id: 'PROJ-123', + priority: 'urgent', }, notetaker: { id: notetakerId, - name: "Updated Nylas Notetaker", + name: 'Updated Nylas Notetaker', meetingSettings: { videoRecording: false, audioRecording: true, - transcription: false - } - } + transcription: false, + }, + }, }; - + console.log(`Request body: ${JSON.stringify(requestBody, null, 2)}`); - + // Update the event const updatedEvent = await nylas.events.update({ identifier: grantId, eventId, requestBody, queryParams: { - calendarId - } + calendarId, + }, }); - + console.log(`Updated event with ID: ${updatedEvent.data.id}`); if (updatedEvent.data.notetaker) { - console.log(`Updated Event Notetaker ID: ${updatedEvent.data.notetaker.id}`); + console.log( + `Updated Event Notetaker ID: ${updatedEvent.data.notetaker.id}` + ); } - + return updatedEvent; } catch (error) { if (error instanceof NylasApiError) { console.error(`Error updating event: ${error.message}`); console.error(`Error details: ${JSON.stringify(error, null, 2)}`); } else if (error instanceof Error) { - console.error(`Unexpected error in updateEventAndNotetaker: ${error.message}`); + console.error( + `Unexpected error in updateEventAndNotetaker: ${error.message}` + ); console.error(`Error type: ${error.constructor.name}`); } throw error; @@ -222,30 +239,34 @@ async function main(): Promise { console.log(`Using API key: ${apiKey.substring(0, 5)}...`); console.log(`Using Grant ID: ${grantId.substring(0, 5)}...`); console.log(`Using Calendar ID: ${calendarId.substring(0, 5)}...`); - + // Create an event with a Notetaker const event = await createEventWithNotetaker(); if (!event || !event.data.id) { - console.error("Failed to create event"); + console.error('Failed to create event'); return; } - + // Get the Notetaker for the event const notetaker = await getEventNotetaker(event.data.id); if (!notetaker || !notetaker.data.id) { console.error(`Failed to get Notetaker for event ${event.data.id}`); return; } - + // Update both the event and its Notetaker - const updatedEvent = await updateEventAndNotetaker(event.data.id, notetaker.data.id); + const updatedEvent = await updateEventAndNotetaker( + event.data.id, + notetaker.data.id + ); if (!updatedEvent) { console.error(`Failed to update event ${event.data.id}`); return; } - - console.log("\n=== Calendar Event with Notetaker Demo Completed Successfully ==="); - + + console.log( + '\n=== Calendar Event with Notetaker Demo Completed Successfully ===' + ); } catch (error) { if (error instanceof NylasApiError) { console.error(`\nNylas API Error: ${error.message}`); @@ -262,4 +283,4 @@ async function main(): Promise { // Run the main function if (require.main === module) { main().catch(console.error); -} \ No newline at end of file +} diff --git a/examples/edge-environment/src/worker.ts b/examples/edge-environment/src/worker.ts index d2f8dc04..73adce2b 100644 --- a/examples/edge-environment/src/worker.ts +++ b/examples/edge-environment/src/worker.ts @@ -1,4 +1,3 @@ - import Nylas, { SendMessageRequest } from 'nylas'; import * as mimeTypes from 'mime-types'; @@ -268,14 +267,16 @@ const HTML_INTERFACE = ` `; // Helper function to parse multipart form data -async function parseFormData(request: Request): Promise<{ [key: string]: any }> { +async function parseFormData( + request: Request +): Promise<{ [key: string]: any }> { const formData = await request.formData(); const result: { [key: string]: any } = {}; - + for (const [key, value] of formData.entries()) { result[key] = value; } - + return result; } @@ -288,7 +289,7 @@ function getContentType(filename: string): string { export default { async fetch(request: Request, env: Env): Promise { const url = new URL(request.url); - + // CORS headers for the response const corsHeaders = { 'Access-Control-Allow-Origin': '*', @@ -317,7 +318,10 @@ export default { // Validate environment variables if (!env.NYLAS_API_KEY || !env.NYLAS_GRANT_ID) { return new Response( - JSON.stringify({ error: 'Missing required environment variables (NYLAS_API_KEY, NYLAS_GRANT_ID)' }), + JSON.stringify({ + error: + 'Missing required environment variables (NYLAS_API_KEY, NYLAS_GRANT_ID)', + }), { status: 500, headers: { 'Content-Type': 'application/json', ...corsHeaders }, @@ -418,13 +422,13 @@ export default { headers: { 'Content-Type': 'application/json', ...corsHeaders }, } ); - } catch (error) { console.error('Error sending email:', error); - + return new Response( JSON.stringify({ - error: error instanceof Error ? error.message : 'Unknown error occurred', + error: + error instanceof Error ? error.message : 'Unknown error occurred', }), { status: 500, @@ -440,4 +444,4 @@ export default { headers: corsHeaders, }); }, -}; \ No newline at end of file +}; diff --git a/examples/esm-only/indes.mjs b/examples/esm-only/indes.mjs new file mode 100644 index 00000000..775dcd52 --- /dev/null +++ b/examples/esm-only/indes.mjs @@ -0,0 +1,81 @@ +/** + * ESM-Only Nylas SDK Example + * + * This example demonstrates how to use the Nylas Node.js SDK in a pure ESM + * (ECMAScript Modules) environment without CommonJS compatibility. + * + * Purpose: + * - Shows ESM import syntax with the Nylas SDK + * - Demonstrates environment variable handling in ESM + * - Provides a simple messages listing example + * + * Usage: + * 1. Copy the parent examples/.env.example to examples/.env + * 2. Fill in your NYLAS_API_KEY and NYLAS_GRANT_ID in the .env file + * 3. Run: node indes.mjs + * + * Requirements: + * - Node.js with ESM support (Node 14+) + * - Valid Nylas API credentials + * - A grant with message access permissions + */ + +import dotenv from 'dotenv'; +import path from 'node:path'; +import Nylas from 'nylas'; +import { logger, maskSecret } from '../utils/logger.mjs'; + +// Load from parent directory since this example lives in a subdirectory +dotenv.config({ path: path.resolve(import.meta.dirname, '../.env') }); + +// Fail fast if credentials are missing to provide clear error messages +const apiKey = process.env.NYLAS_API_KEY || ''; +if (!apiKey) { + throw new Error('NYLAS_API_KEY environment variable is not set'); +} + +const grantId = process.env.NYLAS_GRANT_ID || ''; +if (!grantId) { + throw new Error('NYLAS_GRANT_ID environment variable is not set'); +} + +// Initialize the Nylas client +const nylas = new Nylas({ + apiKey, + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' +}); + + +/** + * Main function to demonstrate basic Nylas SDK usage in ESM environment + */ +async function main() { + try { + logger.info('Listing messages...'); + + // Log runtime config for debugging without exposing sensitive data + logger.debug('Runtime config', { + apiKey: maskSecret(apiKey), + grantId, + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + }); + + // Use basic list operation to verify SDK functionality and connectivity + const messages = await nylas.messages.list({ + identifier: grantId, + }); + + logger.success('Messages listed successfully'); + + // Extract only essential fields to avoid logging sensitive message content + logger.info('Message subjects and ids', messages.data.map(m => ({ id: m.id, subject: m.subject }))); + + } catch (error) { + logger.error('Failed to list messages'); + logger.debug('Error details', error); + // Exit with error code to indicate failure for automation/CI purposes + process.exit(1); + } +} + +main(); \ No newline at end of file diff --git a/examples/esm-only/package-lock.json b/examples/esm-only/package-lock.json new file mode 100644 index 00000000..dd04519c --- /dev/null +++ b/examples/esm-only/package-lock.json @@ -0,0 +1,70 @@ +{ + "name": "esm-only", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "esm-only", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^17.2.2", + "nylas": "file:../../" + } + }, + "../..": { + "name": "nylas", + "version": "7.13.0", + "license": "MIT", + "dependencies": { + "change-case": "^4.1.2", + "form-data-encoder": "^4.1.0", + "formdata-node": "^6.0.3", + "mime-types": "^2.1.35", + "node-fetch": "^3.3.2", + "uuid": "^8.3.2" + }, + "devDependencies": { + "@babel/core": "^7.3.3", + "@types/jest": "^29.5.2", + "@types/mime-types": "^2.1.2", + "@types/node": "^22.15.21", + "@types/uuid": "^8.3.4", + "@typescript-eslint/eslint-plugin": "^2.25.0", + "@typescript-eslint/parser": "^2.25.0", + "eslint": "^5.14.0", + "eslint-config-prettier": "^4.0.0", + "eslint-plugin-custom-rules": "^0.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-prettier": "^3.0.1", + "jest": "^29.6.1", + "jest-fetch-mock": "^3.0.3", + "prettier": "^3.5.3", + "ts-jest": "^29.1.1", + "typedoc": "^0.28.4", + "typedoc-plugin-rename-defaults": "^0.7.3", + "typescript": "^5.8.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/dotenv": { + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", + "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/nylas": { + "resolved": "../..", + "link": true + } + } +} diff --git a/examples/esm-only/package.json b/examples/esm-only/package.json new file mode 100644 index 00000000..f94ea3bd --- /dev/null +++ b/examples/esm-only/package.json @@ -0,0 +1,16 @@ +{ + "name": "esm-only", + "version": "1.0.0", + "description": "An esm-only example of the Nylas NodeJS SDK usage", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "nylas": "file:../../", + "dotenv": "^17.2.2" + } +} diff --git a/examples/folders/folders.ts b/examples/folders/folders.ts index 07bf2bff..8a7ca062 100644 --- a/examples/folders/folders.ts +++ b/examples/folders/folders.ts @@ -11,7 +11,7 @@ const nylas = new Nylas({ /** * 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. */ @@ -25,7 +25,7 @@ async function listFolders() { }); console.log('Found', folders.data.length, 'folders'); - + folders.data.forEach((folder, index) => { console.log(`${index + 1}. ${folder.name} (ID: ${folder.id})`); if (folder.parentId) { @@ -39,7 +39,7 @@ async function listFolders() { // 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: { @@ -47,11 +47,15 @@ async function listFolders() { }, }); - console.log('Found', foldersWithHidden.data.length, 'folders (including hidden)'); - + 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: { @@ -59,9 +63,11 @@ async function listFolders() { }, }); - const parentFolders = parentFoldersWithHidden.data.filter(folder => !folder.parentId); + 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) { @@ -75,7 +81,6 @@ async function listFolders() { } console.log(''); }); - } catch (error) { console.error('Error listing folders:', error); } @@ -85,4 +90,4 @@ if (!GRANT_ID) { console.error('Please set NYLAS_GRANT_ID in your environment variables'); } else { listFolders().catch(console.error); -} +} diff --git a/examples/messages/cli-interface.ts b/examples/messages/cli-interface.ts index 3235e7df..7dac24be 100644 --- a/examples/messages/cli-interface.ts +++ b/examples/messages/cli-interface.ts @@ -12,19 +12,25 @@ interface CliOptions { isPlaintext: boolean; } -async function getCliOptions(fileManager: TestFileManager): Promise { +async function getCliOptions( + fileManager: TestFileManager +): Promise { console.log(chalk.blue.bold('\nšŸš€ Nylas Send Attachments Examples\n')); - + fileManager.checkFileStatus(); - + const smallFiles = fileManager.getSmallFiles(); const largeFiles = fileManager.getLargeFiles(); - + if (smallFiles.length === 0 && largeFiles.length === 0) { - console.log(chalk.red('\nāŒ No test files found! Please create the required test files in attachments/')); + console.log( + chalk.red( + '\nāŒ No test files found! Please create the required test files in attachments/' + ) + ); process.exit(1); } - + const answers = await inquirer.prompt([ { type: 'list', @@ -35,71 +41,115 @@ async function getCliOptions(fileManager: TestFileManager): Promise { name: '🌊 Streams (advanced)', value: 'stream' }, { name: 'šŸ’¾ Buffers (small files)', value: 'buffer' }, { name: 'šŸ“ String content (dynamic)', value: 'string' }, - ] + ], }, { type: 'list', name: 'attachmentSize', message: 'What size attachments?', choices: [ - { name: `šŸ“Ž Small (${smallFiles.length} available)`, value: 'small', disabled: smallFiles.length === 0 }, - { name: `šŸ“‹ Large (${largeFiles.length} available)`, value: 'large', disabled: largeFiles.length === 0 } - ] + { + name: `šŸ“Ž Small (${smallFiles.length} available)`, + value: 'small', + disabled: smallFiles.length === 0, + }, + { + name: `šŸ“‹ Large (${largeFiles.length} available)`, + value: 'large', + disabled: largeFiles.length === 0, + }, + ], }, { type: 'input', name: 'testEmail', message: 'Recipient email address:', default: process.env.TEST_EMAIL || '', - validate: (input: string) => input.includes('@') || 'Please enter a valid email address' + validate: (input: string) => + input.includes('@') || 'Please enter a valid email address', }, { type: 'confirm', name: 'isPlaintext', message: 'Send as plaintext (no HTML rendering)?', - default: false - } + default: false, + }, ]); return answers as CliOptions; } -async function runExample(examples: SendAttachmentsExamples, fileManager: TestFileManager, options: CliOptions): Promise { +async function runExample( + examples: SendAttachmentsExamples, + fileManager: TestFileManager, + options: CliOptions +): Promise { const { format, testEmail, attachmentSize, isPlaintext } = options; - + if (!testEmail) { console.log(chalk.yellow('āš ļø No email provided. Skipping send.')); return; } - + try { - console.log(chalk.blue(`\nšŸ“¤ Running ${format} attachment example (${attachmentSize} files)${isPlaintext ? ' in plaintext mode' : ''}...\n`)); - + console.log( + chalk.blue( + `\nšŸ“¤ Running ${format} attachment example (${attachmentSize} files)${isPlaintext ? ' in plaintext mode' : ''}...\n` + ) + ); + let result: NylasResponse; const isLarge = attachmentSize === 'large'; - + // Route to the appropriate example based on format switch (format) { case 'file': - result = await examples.sendFilePathAttachments(fileManager, testEmail, isLarge, isPlaintext); + result = await examples.sendFilePathAttachments( + fileManager, + testEmail, + isLarge, + isPlaintext + ); break; case 'stream': - result = await examples.sendStreamAttachments(fileManager, testEmail, isLarge, isPlaintext); + result = await examples.sendStreamAttachments( + fileManager, + testEmail, + isLarge, + isPlaintext + ); break; case 'buffer': - result = await examples.sendBufferAttachments(fileManager, testEmail, isLarge, isPlaintext); + result = await examples.sendBufferAttachments( + fileManager, + testEmail, + isLarge, + isPlaintext + ); break; case 'string': - result = await examples.sendStringAttachments(fileManager, testEmail, isLarge, isPlaintext); + result = await examples.sendStringAttachments( + fileManager, + testEmail, + isLarge, + isPlaintext + ); break; default: - result = await examples.sendAttachmentsByFormat(fileManager, format, testEmail, attachmentSize, isPlaintext); + result = await examples.sendAttachmentsByFormat( + fileManager, + format, + testEmail, + attachmentSize, + isPlaintext + ); } - + console.log(chalk.green.bold('\nāœ… Message sent successfully!')); console.log(chalk.green(`šŸ“§ Message ID: ${result.data.id}`)); - console.log(chalk.green(`šŸ“Ž Attachments: ${result.data.attachments?.length || 0}`)); - + console.log( + chalk.green(`šŸ“Ž Attachments: ${result.data.attachments?.length || 0}`) + ); } catch (error) { console.log(chalk.red.bold('\nāŒ Error sending message:')); if (error instanceof NylasApiError) { @@ -110,28 +160,39 @@ async function runExample(examples: SendAttachmentsExamples, fileManager: TestFi } } -async function runBatchMode(examples: SendAttachmentsExamples, fileManager: TestFileManager, size: 'small' | 'large', format: FileFormat, email?: string, isPlaintext: boolean = false): Promise { +async function runBatchMode( + examples: SendAttachmentsExamples, + fileManager: TestFileManager, + size: 'small' | 'large', + format: FileFormat, + email?: string, + isPlaintext: boolean = false +): Promise { const options: CliOptions = { attachmentSize: size, format, testEmail: email, - isPlaintext + isPlaintext, }; - + console.log(chalk.blue.bold('\nšŸš€ Nylas Send Attachments (Batch Mode)\n')); fileManager.checkFileStatus(); - + await runExample(examples, fileManager, options); } -export async function startCli(examples: SendAttachmentsExamples, fileManager: TestFileManager, testEmail: string): Promise { +export async function startCli( + examples: SendAttachmentsExamples, + fileManager: TestFileManager, + testEmail: string +): Promise { const program = new Command(); - + program .name('send-attachments') .description('Nylas SDK attachment examples') .version('1.0.0'); - + program .command('interactive', { isDefault: true }) .description('Run interactive examples') @@ -139,27 +200,49 @@ export async function startCli(examples: SendAttachmentsExamples, fileManager: T const options = await getCliOptions(fileManager); await runExample(examples, fileManager, options); }); - + program .command('small') .description('Send small attachments') - .option('-f, --format ', 'format (file|stream|buffer|string)', 'file') + .option( + '-f, --format ', + 'format (file|stream|buffer|string)', + 'file' + ) .option('-e, --email ', 'recipient email') .option('--plaintext', 'send as plaintext', false) .action(async (options) => { - await runBatchMode(examples, fileManager, 'small', options.format as FileFormat, options.email || testEmail, Boolean(options.plaintext)); + await runBatchMode( + examples, + fileManager, + 'small', + options.format as FileFormat, + options.email || testEmail, + Boolean(options.plaintext) + ); }); - + program .command('large') .description('Send large attachment') - .option('-f, --format ', 'format (file|stream|buffer|string)', 'file') + .option( + '-f, --format ', + 'format (file|stream|buffer|string)', + 'file' + ) .option('-e, --email ', 'recipient email') .option('--plaintext', 'send as plaintext', false) .action(async (options) => { - await runBatchMode(examples, fileManager, 'large', options.format as FileFormat, options.email || testEmail, Boolean(options.plaintext)); + await runBatchMode( + examples, + fileManager, + 'large', + options.format as FileFormat, + options.email || testEmail, + Boolean(options.plaintext) + ); }); - + program .command('status') .description('Check test files') @@ -167,6 +250,6 @@ export async function startCli(examples: SendAttachmentsExamples, fileManager: T console.log(chalk.blue.bold('\nšŸ“ Test Files Status\n')); fileManager.checkFileStatus(); }); - + await program.parseAsync(); -} \ No newline at end of file +} diff --git a/examples/messages/examples/buffer-attachments.ts b/examples/messages/examples/buffer-attachments.ts index 57bff8a3..2e87b682 100644 --- a/examples/messages/examples/buffer-attachments.ts +++ b/examples/messages/examples/buffer-attachments.ts @@ -1,5 +1,5 @@ import * as dotenv from 'dotenv'; - import Nylas, { NylasResponse, Message, SendMessageRequest } from 'nylas'; +import Nylas, { NylasResponse, Message, SendMessageRequest } from 'nylas'; import * as path from 'path'; import * as process from 'process'; import { TestFileManager } from '../utils/attachment-file-manager'; @@ -10,22 +10,27 @@ dotenv.config({ path: path.resolve(__dirname, '../../.env') }); // Initialize the Nylas client const nylas = new Nylas({ apiKey: process.env.NYLAS_API_KEY || '', - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); const grantId: string = process.env.NYLAS_GRANT_ID || ''; /** * Example 3: Buffer Attachments (For Small Files) - * + * * Loads the entire file into memory as a Buffer. * Good for small files or when you need to process content. */ -export async function sendBufferAttachments(fileManager: TestFileManager, recipientEmail: string, large: boolean = false, isPlaintext: boolean = false): Promise> { +export async function sendBufferAttachments( + fileManager: TestFileManager, + recipientEmail: string, + large: boolean = false, + isPlaintext: boolean = false +): Promise> { console.log('šŸ’¾ Sending attachments using buffers...'); - + let sizeDescription; - + let files; if (large) { // Send one large attachment @@ -38,13 +43,13 @@ export async function sendBufferAttachments(fileManager: TestFileManager, recipi } // Create attachment using a buffer and use file info for name/type - const bufferAttachments = files.map(file => ({ + const bufferAttachments = files.map((file) => ({ filename: file.filename, contentType: file.contentType, content: file.asBuffer(), size: file.size, })); - + const requestBody: SendMessageRequest = { to: [{ name: 'Test Recipient', email: recipientEmail }], subject: 'Nylas SDK - Buffer Attachments', @@ -56,15 +61,15 @@ export async function sendBufferAttachments(fileManager: TestFileManager, recipi

Good for small files when you need the content in memory.

`, attachments: bufferAttachments, - isPlaintext + isPlaintext, }; - + // For large files, use a longer timeout (5 minutes) const overrides = large ? { timeout: 300 } : undefined; - + return await nylas.messages.send({ identifier: grantId, requestBody, - overrides + overrides, }); -} \ No newline at end of file +} diff --git a/examples/messages/examples/file-path-attachments.ts b/examples/messages/examples/file-path-attachments.ts index 780632f6..abb9a534 100644 --- a/examples/messages/examples/file-path-attachments.ts +++ b/examples/messages/examples/file-path-attachments.ts @@ -2,7 +2,10 @@ import * as dotenv from 'dotenv'; import Nylas, { NylasResponse, Message, SendMessageRequest } from 'nylas'; import * as path from 'path'; import * as process from 'process'; -import { createFileRequestBuilder, TestFileManager } from '../utils/attachment-file-manager'; +import { + createFileRequestBuilder, + TestFileManager, +} from '../utils/attachment-file-manager'; // Load environment variables from .env file dotenv.config({ path: path.resolve(__dirname, '../../.env') }); @@ -10,23 +13,28 @@ dotenv.config({ path: path.resolve(__dirname, '../../.env') }); // Initialize the Nylas client const nylas = new Nylas({ apiKey: process.env.NYLAS_API_KEY || '', - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); const grantId: string = process.env.NYLAS_GRANT_ID || ''; /** * Example 1: File Path Attachments (Most Common & Efficient) - * + * * This is the recommended approach for most use cases. * Uses streams internally for memory efficiency. */ -export async function sendFilePathAttachments(fileManager: TestFileManager, recipientEmail: string, large: boolean = false, isPlaintext: boolean = false): Promise> { +export async function sendFilePathAttachments( + fileManager: TestFileManager, + recipientEmail: string, + large: boolean = false, + isPlaintext: boolean = false +): Promise> { console.log('šŸ“ Sending attachments using file paths...'); - + let attachments; let sizeDescription; - + if (large) { // Send one large attachment const file = fileManager.getLargeFiles()[0]; @@ -35,7 +43,7 @@ export async function sendFilePathAttachments(fileManager: TestFileManager, reci } else { // Send multiple small attachments const files = fileManager.getSmallFiles().slice(0, 2); - attachments = files.map(file => createFileRequestBuilder(file.path)); + attachments = files.map((file) => createFileRequestBuilder(file.path)); sizeDescription = 'small'; } @@ -51,7 +59,7 @@ export async function sendFilePathAttachments(fileManager: TestFileManager, reci

Attachment size: ${sizeDescription} (${attachments.length} file${attachments.length > 1 ? 's' : ''})

`, attachments, - isPlaintext + isPlaintext, }; // For large files, use a longer timeout (5 minutes) @@ -60,6 +68,6 @@ export async function sendFilePathAttachments(fileManager: TestFileManager, reci return await nylas.messages.send({ identifier: grantId, requestBody, - overrides + overrides, }); -} \ No newline at end of file +} diff --git a/examples/messages/examples/flexible-attachments.ts b/examples/messages/examples/flexible-attachments.ts index 86f7d77c..a3cf8893 100644 --- a/examples/messages/examples/flexible-attachments.ts +++ b/examples/messages/examples/flexible-attachments.ts @@ -1,5 +1,10 @@ import * as dotenv from 'dotenv'; -import Nylas, { NylasResponse, Message, SendMessageRequest, CreateAttachmentRequest } from 'nylas'; +import Nylas, { + NylasResponse, + Message, + SendMessageRequest, + CreateAttachmentRequest, +} from 'nylas'; import * as path from 'path'; import * as process from 'process'; import { TestFileManager, FileFormat } from '../utils/attachment-file-manager'; @@ -10,7 +15,7 @@ dotenv.config({ path: path.resolve(__dirname, '../../.env') }); // Initialize the Nylas client const nylas = new Nylas({ apiKey: process.env.NYLAS_API_KEY || '', - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); const grantId: string = process.env.NYLAS_GRANT_ID || ''; @@ -18,25 +23,34 @@ const grantId: string = process.env.NYLAS_GRANT_ID || ''; /** * Flexible attachment sending based on format choice */ -export async function sendAttachmentsByFormat(fileManager: TestFileManager, format: FileFormat, recipientEmail: string, attachmentSize: 'small' | 'large' = 'small', isPlaintext: boolean = false): Promise> { - +export async function sendAttachmentsByFormat( + fileManager: TestFileManager, + format: FileFormat, + recipientEmail: string, + attachmentSize: 'small' | 'large' = 'small', + isPlaintext: boolean = false +): Promise> { let attachments: CreateAttachmentRequest[] = []; let subject: string; - + if (attachmentSize === 'small') { // Send two small attachments const files = fileManager.getSmallFiles().slice(0, 2); for (const file of files) { - attachments.push(fileManager.createAttachmentRequest(file.filename, format)); + attachments.push( + fileManager.createAttachmentRequest(file.filename, format) + ); } subject = `Nylas SDK - Small Attachments (${format} format)`; } else { // Send one large attachment const file = fileManager.getLargeFiles()[0]; - attachments.push(fileManager.createAttachmentRequest(file.filename, format)); + attachments.push( + fileManager.createAttachmentRequest(file.filename, format) + ); subject = `Nylas SDK - Large Attachment (${format} format)`; } - + const requestBody: SendMessageRequest = { to: [{ name: 'Test Recipient', email: recipientEmail }], subject, @@ -47,19 +61,19 @@ export async function sendAttachmentsByFormat(fileManager: TestFileManager, form

This message demonstrates sending attachments using the ${format} format.

Files attached: ${attachments.length}

    - ${attachments.map(att => `
  • ${att.filename} (${att.size} bytes)
  • `).join('')} + ${attachments.map((att) => `
  • ${att.filename} (${att.size} bytes)
  • `).join('')}
`, attachments, - isPlaintext + isPlaintext, }; - + // For large files, use a longer timeout (5 minutes) const overrides = attachmentSize === 'large' ? { timeout: 300 } : undefined; - + return await nylas.messages.send({ identifier: grantId, requestBody, - overrides + overrides, }); -} \ No newline at end of file +} diff --git a/examples/messages/examples/index.ts b/examples/messages/examples/index.ts index 7e18192d..96ff842a 100644 --- a/examples/messages/examples/index.ts +++ b/examples/messages/examples/index.ts @@ -5,9 +5,35 @@ import { sendStringAttachments } from './string-attachments'; import { sendAttachmentsByFormat } from './flexible-attachments'; export type SendAttachmentsExamples = { - sendFilePathAttachments: (fileManager: Parameters[0], recipientEmail: string, large?: boolean, isPlaintext?: boolean) => ReturnType, - sendStreamAttachments: (fileManager: Parameters[0], recipientEmail: string, large?: boolean, isPlaintext?: boolean) => ReturnType, - sendBufferAttachments: (fileManager: Parameters[0], recipientEmail: string, large?: boolean, isPlaintext?: boolean) => ReturnType, - sendStringAttachments: (fileManager: Parameters[0], recipientEmail: string, large?: boolean, isPlaintext?: boolean) => ReturnType, - sendAttachmentsByFormat: (fileManager: Parameters[0], format: Parameters[1], recipientEmail: string, attachmentSize?: Parameters[3], isPlaintext?: boolean) => ReturnType -}; \ No newline at end of file + sendFilePathAttachments: ( + fileManager: Parameters[0], + recipientEmail: string, + large?: boolean, + isPlaintext?: boolean + ) => ReturnType; + sendStreamAttachments: ( + fileManager: Parameters[0], + recipientEmail: string, + large?: boolean, + isPlaintext?: boolean + ) => ReturnType; + sendBufferAttachments: ( + fileManager: Parameters[0], + recipientEmail: string, + large?: boolean, + isPlaintext?: boolean + ) => ReturnType; + sendStringAttachments: ( + fileManager: Parameters[0], + recipientEmail: string, + large?: boolean, + isPlaintext?: boolean + ) => ReturnType; + sendAttachmentsByFormat: ( + fileManager: Parameters[0], + format: Parameters[1], + recipientEmail: string, + attachmentSize?: Parameters[3], + isPlaintext?: boolean + ) => ReturnType; +}; diff --git a/examples/messages/examples/stream-attachments.ts b/examples/messages/examples/stream-attachments.ts index ff9b3d72..a1436673 100644 --- a/examples/messages/examples/stream-attachments.ts +++ b/examples/messages/examples/stream-attachments.ts @@ -1,5 +1,10 @@ import * as dotenv from 'dotenv'; -import Nylas, { NylasResponse, Message, SendMessageRequest, CreateAttachmentRequest } from 'nylas'; +import Nylas, { + NylasResponse, + Message, + SendMessageRequest, + CreateAttachmentRequest, +} from 'nylas'; import * as path from 'path'; import * as process from 'process'; import { TestFileManager } from '../utils/attachment-file-manager'; @@ -10,37 +15,44 @@ dotenv.config({ path: path.resolve(__dirname, '../../.env') }); // Initialize the Nylas client const nylas = new Nylas({ apiKey: process.env.NYLAS_API_KEY || '', - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); const grantId: string = process.env.NYLAS_GRANT_ID || ''; /** * Example 2: Stream Attachments (For More Control) - * + * * Useful when you're working with streams from other sources * or need more control over the stream processing. */ -export async function sendStreamAttachments(fileManager: TestFileManager, recipientEmail: string, large: boolean = false, isPlaintext: boolean = false): Promise> { +export async function sendStreamAttachments( + fileManager: TestFileManager, + recipientEmail: string, + large: boolean = false, + isPlaintext: boolean = false +): Promise> { console.log('🌊 Sending attachments using streams...'); - + let attachments: CreateAttachmentRequest[] = []; let sizeDescription; - + if (large) { // Send one large attachment const file = fileManager.getLargeFiles()[0]; - attachments = [{ - filename: file.filename, - contentType: file.contentType, - content: file.asStream(), - size: file.size, - }]; + attachments = [ + { + filename: file.filename, + contentType: file.contentType, + content: file.asStream(), + size: file.size, + }, + ]; sizeDescription = 'large'; } else { // Send multiple small attachments const files = fileManager.getSmallFiles().slice(0, 2); - attachments = files.map(file => ({ + attachments = files.map((file) => ({ filename: file.filename, contentType: file.contentType, content: file.asStream(), @@ -48,7 +60,7 @@ export async function sendStreamAttachments(fileManager: TestFileManager, recipi })); sizeDescription = 'small'; } - + const requestBody: SendMessageRequest = { to: [{ name: 'Test Recipient', email: recipientEmail }], subject: `Nylas SDK - Stream Attachments (${sizeDescription})`, @@ -61,15 +73,15 @@ export async function sendStreamAttachments(fileManager: TestFileManager, recipi

Attachment size: ${sizeDescription} (${attachments.length} file${attachments.length > 1 ? 's' : ''})

`, attachments, - isPlaintext + isPlaintext, }; - + // For large files, use a longer timeout (5 minutes) const overrides = large ? { timeout: 300 } : undefined; - + return await nylas.messages.send({ identifier: grantId, requestBody, - overrides + overrides, }); -} \ No newline at end of file +} diff --git a/examples/messages/examples/string-attachments.ts b/examples/messages/examples/string-attachments.ts index 4e92afd6..932fb909 100644 --- a/examples/messages/examples/string-attachments.ts +++ b/examples/messages/examples/string-attachments.ts @@ -1,5 +1,10 @@ import * as dotenv from 'dotenv'; -import Nylas, { NylasResponse, Message, SendMessageRequest, CreateAttachmentRequest } from 'nylas'; +import Nylas, { + NylasResponse, + Message, + SendMessageRequest, + CreateAttachmentRequest, +} from 'nylas'; import { TestFileManager } from '../utils/attachment-file-manager'; import * as path from 'path'; import * as process from 'process'; @@ -10,37 +15,45 @@ dotenv.config({ path: path.resolve(__dirname, '../../.env') }); // Initialize the Nylas client const nylas = new Nylas({ apiKey: process.env.NYLAS_API_KEY || '', - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); const grantId: string = process.env.NYLAS_GRANT_ID || ''; /** * Example 4: String Content Attachments (Base64 Encoded Files) - * + * * Perfect for sending existing files as base64 encoded strings. * This example pulls the same files used by other examples but encodes them as base64 strings. */ -export async function sendStringAttachments(fileManager: TestFileManager, recipientEmail: string, large: boolean = false, isPlaintext: boolean = false): Promise> { +export async function sendStringAttachments( + fileManager: TestFileManager, + recipientEmail: string, + large: boolean = false, + isPlaintext: boolean = false +): Promise> { console.log('šŸ“ Sending base64 encoded file attachments as strings...'); - + let stringAttachments: CreateAttachmentRequest[] = []; let sizeDescription = ''; - + if (large) { // Send one large attachment - use the large PDF file const largeFiles = fileManager.getLargeFiles(); if (largeFiles.length > 0) { - const file = largeFiles.find(f => f.filename.includes('pdf')) || largeFiles[0]; + const file = + largeFiles.find((f) => f.filename.includes('pdf')) || largeFiles[0]; const fileBuffer = file.asBuffer(); const base64Content = fileBuffer.toString('base64'); - - stringAttachments = [{ - filename: file.filename, - contentType: file.contentType, - content: base64Content, - size: Buffer.byteLength(base64Content, 'utf8'), - }]; + + stringAttachments = [ + { + filename: file.filename, + contentType: file.contentType, + content: base64Content, + size: Buffer.byteLength(base64Content, 'utf8'), + }, + ]; sizeDescription = 'large'; } else { throw new Error('No large files available for testing'); @@ -50,15 +63,17 @@ export async function sendStringAttachments(fileManager: TestFileManager, recipi const smallFiles = fileManager.getSmallFiles(); if (smallFiles.length >= 2) { // Get the text file and image file - const textFile = smallFiles.find(f => f.filename.includes('.txt')) || smallFiles[0]; - const imageFile = smallFiles.find(f => f.filename.includes('.jpg')) || smallFiles[1]; - + const textFile = + smallFiles.find((f) => f.filename.includes('.txt')) || smallFiles[0]; + const imageFile = + smallFiles.find((f) => f.filename.includes('.jpg')) || smallFiles[1]; + const files = [textFile, imageFile]; - - stringAttachments = files.map(file => { + + stringAttachments = files.map((file) => { const fileBuffer = file.asBuffer(); const base64Content = fileBuffer.toString('base64'); - + return { filename: file.filename, contentType: file.contentType, @@ -71,7 +86,7 @@ export async function sendStringAttachments(fileManager: TestFileManager, recipi throw new Error('Not enough small files available for testing'); } } - + const requestBody: SendMessageRequest = { to: [{ name: 'Test Recipient', email: recipientEmail }], subject: `Nylas SDK - Base64 String Attachments (${sizeDescription})`, @@ -83,19 +98,19 @@ export async function sendStringAttachments(fileManager: TestFileManager, recipi

Files are converted from the same test files used in other examples.

Attachment size: ${sizeDescription} (${stringAttachments.length} file${stringAttachments.length > 1 ? 's' : ''})

    - ${stringAttachments.map(att => `
  • ${att.filename} (${att.size} bytes base64 encoded)
  • `).join('')} + ${stringAttachments.map((att) => `
  • ${att.filename} (${att.size} bytes base64 encoded)
  • `).join('')}
`, attachments: stringAttachments, - isPlaintext + isPlaintext, }; - + // For large files, use a longer timeout (5 minutes) const overrides = large ? { timeout: 300 } : undefined; - + return await nylas.messages.send({ identifier: grantId, requestBody, - overrides + overrides, }); -} \ No newline at end of file +} diff --git a/examples/messages/messages.ts b/examples/messages/messages.ts index cfb1f484..f1f6c946 100644 --- a/examples/messages/messages.ts +++ b/examples/messages/messages.ts @@ -6,7 +6,7 @@ import Nylas, { NylasApiError, NylasResponse, SendMessageRequest, - UpdateMessageRequest + UpdateMessageRequest, } from 'nylas'; import * as path from 'path'; import * as process from 'process'; @@ -28,7 +28,7 @@ if (!grantId) { // Initialize the Nylas client const nylas = new Nylas({ apiKey, - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); /** @@ -36,7 +36,7 @@ const nylas = new Nylas({ */ async function demonstrateMessageFields(): Promise { console.log('\n=== Demonstrating Message Fields ==='); - + try { // 1. List messages with standard fields console.log('\n--- Listing messages with standard fields ---'); @@ -44,15 +44,21 @@ async function demonstrateMessageFields(): Promise { identifier: grantId, queryParams: { fields: MessageFields.STANDARD, - limit: 2 - } + limit: 2, + }, }); - - console.log(`Found ${standardMessages.data.length} messages with standard fields`); + + console.log( + `Found ${standardMessages.data.length} messages with standard fields` + ); for (const message of standardMessages.data) { console.log(`- ${message.id}: ${message.subject || '(no subject)'}`); - console.log(` From: ${message.from?.map(f => `${f.name} <${f.email}>`).join(', ') || 'Unknown'}`); - console.log(` Tracking Options: ${message.trackingOptions ? 'Present' : 'Not present'}`); + console.log( + ` From: ${message.from?.map((f) => `${f.name} <${f.email}>`).join(', ') || 'Unknown'}` + ); + console.log( + ` Tracking Options: ${message.trackingOptions ? 'Present' : 'Not present'}` + ); console.log(` Headers: ${message.headers ? 'Present' : 'Not present'}`); console.log(` Raw MIME: ${message.rawMime ? 'Present' : 'Not present'}`); } @@ -63,17 +69,21 @@ async function demonstrateMessageFields(): Promise { identifier: grantId, queryParams: { fields: MessageFields.INCLUDE_TRACKING_OPTIONS, - limit: 2 - } + limit: 2, + }, }); - - console.log(`Found ${trackingMessages.data.length} messages with tracking options`); + + console.log( + `Found ${trackingMessages.data.length} messages with tracking options` + ); for (const message of trackingMessages.data) { console.log(`- ${message.id}: ${message.subject || '(no subject)'}`); if (message.trackingOptions) { console.log(` Tracking Options:`); console.log(` Opens: ${message.trackingOptions.opens}`); - console.log(` Thread Replies: ${message.trackingOptions.threadReplies}`); + console.log( + ` Thread Replies: ${message.trackingOptions.threadReplies}` + ); console.log(` Links: ${message.trackingOptions.links}`); console.log(` Label: ${message.trackingOptions.label}`); } else { @@ -87,17 +97,19 @@ async function demonstrateMessageFields(): Promise { identifier: grantId, queryParams: { fields: MessageFields.INCLUDE_HEADERS, - limit: 2 - } + limit: 2, + }, }); - + console.log(`Found ${headerMessages.data.length} messages with headers`); for (const message of headerMessages.data) { console.log(`- ${message.id}: ${message.subject || '(no subject)'}`); if (message.headers && message.headers.length > 0) { console.log(` Headers (showing first 3):`); - message.headers.slice(0, 3).forEach(header => { - console.log(` ${header.name}: ${header.value.substring(0, 100)}${header.value.length > 100 ? '...' : ''}`); + message.headers.slice(0, 3).forEach((header) => { + console.log( + ` ${header.name}: ${header.value.substring(0, 100)}${header.value.length > 100 ? '...' : ''}` + ); }); if (message.headers.length > 3) { console.log(` ... and ${message.headers.length - 3} more headers`); @@ -106,13 +118,14 @@ async function demonstrateMessageFields(): Promise { console.log(` No headers available`); } } - } catch (error) { if (error instanceof NylasApiError) { console.error(`Error demonstrating message fields: ${error.message}`); console.error(`Error details: ${JSON.stringify(error, null, 2)}`); } else if (error instanceof Error) { - console.error(`Unexpected error in demonstrateMessageFields: ${error.message}`); + console.error( + `Unexpected error in demonstrateMessageFields: ${error.message}` + ); } throw error; } @@ -123,51 +136,60 @@ async function demonstrateMessageFields(): Promise { */ async function demonstrateRawMime(): Promise { console.log('\n=== Demonstrating Raw MIME Data ==='); - + try { // First, get a message ID const messages = await nylas.messages.list({ identifier: grantId, queryParams: { - limit: 1 - } + limit: 1, + }, }); - + if (messages.data.length === 0) { console.log('No messages available to demonstrate raw MIME'); return; } - + const messageId = messages.data[0].id; console.log(`Getting raw MIME data for message: ${messageId}`); - + // Get the message with raw MIME data const rawMessage = await nylas.messages.find({ identifier: grantId, messageId, queryParams: { - fields: MessageFields.RAW_MIME - } + fields: MessageFields.RAW_MIME, + }, }); - + console.log('Raw MIME Response:'); console.log(`- ID: ${rawMessage.data.id}`); console.log(`- Grant ID: ${rawMessage.data.grantId}`); console.log(`- Object: ${rawMessage.data.object}`); - + if (rawMessage.data.rawMime) { - console.log(`- Raw MIME Data: ${rawMessage.data.rawMime.substring(0, 100)}... (truncated)`); - console.log(`- Raw MIME Length: ${rawMessage.data.rawMime.length} characters`); - + console.log( + `- Raw MIME Data: ${rawMessage.data.rawMime.substring(0, 100)}... (truncated)` + ); + console.log( + `- Raw MIME Length: ${rawMessage.data.rawMime.length} characters` + ); + // Note: When requesting raw_mime, only grant_id, object, id, and raw_mime fields are returned - console.log('\nNote: When requesting raw_mime, only specific fields are returned:'); + console.log( + '\nNote: When requesting raw_mime, only specific fields are returned:' + ); console.log(`- Subject: ${rawMessage.data.subject || 'Not included'}`); - console.log(`- Body: ${rawMessage.data.body ? 'Present' : 'Not included'}`); - console.log(`- From: ${rawMessage.data.from ? 'Present' : 'Not included'}`); + console.log( + `- Body: ${rawMessage.data.body ? 'Present' : 'Not included'}` + ); + console.log( + `- From: ${rawMessage.data.from ? 'Present' : 'Not included'}` + ); } else { console.log('- Raw MIME Data: Not available'); } - } catch (error) { if (error instanceof NylasApiError) { console.error(`Error demonstrating raw MIME: ${error.message}`); @@ -183,22 +205,28 @@ async function demonstrateRawMime(): Promise { */ async function demonstrateMessageSending(): Promise | null> { console.log('\n=== Demonstrating Message Sending ==='); - + try { const testEmail = process.env.TEST_EMAIL; if (!testEmail) { - console.log('TEST_EMAIL environment variable not set. Skipping message sending demo.'); - console.log('Set TEST_EMAIL=your-email@example.com to test message sending.'); + console.log( + 'TEST_EMAIL environment variable not set. Skipping message sending demo.' + ); + console.log( + 'Set TEST_EMAIL=your-email@example.com to test message sending.' + ); return null; } - + console.log(`Sending test message to: ${testEmail}`); - + const requestBody: SendMessageRequest = { - to: [{ - name: 'Test Recipient', - email: testEmail - }], + to: [ + { + name: 'Test Recipient', + email: testEmail, + }, + ], subject: 'Nylas SDK Messages Example - Testing New Features', body: ` @@ -215,29 +243,32 @@ async function demonstrateMessageSending(): Promise | nul

Best regards,
The Nylas SDK Team

- ` + `, // Note: Tracking options are configured at the API/provider level, not in the request }; - + console.log('Sending message with tracking...'); const sentMessage = await nylas.messages.send({ identifier: grantId, - requestBody + requestBody, }); - + console.log(`Message sent successfully!`); console.log(`- Message ID: ${sentMessage.data.id}`); console.log(`- Subject: ${sentMessage.data.subject}`); - console.log(`- To: ${sentMessage.data.to?.map(t => `${t.name} <${t.email}>`).join(', ')}`); - + console.log( + `- To: ${sentMessage.data.to?.map((t) => `${t.name} <${t.email}>`).join(', ')}` + ); + return sentMessage; - } catch (error) { if (error instanceof NylasApiError) { console.error(`Error sending message: ${error.message}`); console.error(`Error details: ${JSON.stringify(error, null, 2)}`); } else if (error instanceof Error) { - console.error(`Unexpected error in demonstrateMessageSending: ${error.message}`); + console.error( + `Unexpected error in demonstrateMessageSending: ${error.message}` + ); } return null; } @@ -251,7 +282,9 @@ async function demonstratePlaintextMessageSending(): Promise `${t.name} <${t.email}>`).join(', ')}`); + console.log( + `- To: ${sentMessage.data.to?.map((t) => `${t.name} <${t.email}>`).join(', ')}` + ); return sentMessage; } catch (error) { @@ -278,7 +313,9 @@ async function demonstratePlaintextMessageSending(): Promise { console.log('\n=== Demonstrating Message Update ==='); - + try { console.log(`Updating message: ${messageId}`); - + const updateRequest: UpdateMessageRequest = { starred: true, unread: false, @@ -300,27 +337,30 @@ async function demonstrateMessageUpdate(messageId: string): Promise { example_type: 'sdk_demo', feature_test: 'tracking_and_mime', updated_at: new Date().toISOString(), - status: 'processed' - } + status: 'processed', + }, }; - + const updatedMessage = await nylas.messages.update({ identifier: grantId, messageId, - requestBody: updateRequest + requestBody: updateRequest, }); - + console.log('Message updated successfully!'); console.log(`- Message ID: ${updatedMessage.data.id}`); console.log(`- Starred: ${updatedMessage.data.starred}`); console.log(`- Unread: ${updatedMessage.data.unread}`); - console.log(`- Metadata: ${JSON.stringify(updatedMessage.data.metadata, null, 2)}`); - + console.log( + `- Metadata: ${JSON.stringify(updatedMessage.data.metadata, null, 2)}` + ); } catch (error) { if (error instanceof NylasApiError) { console.error(`Error updating message: ${error.message}`); } else if (error instanceof Error) { - console.error(`Unexpected error in demonstrateMessageUpdate: ${error.message}`); + console.error( + `Unexpected error in demonstrateMessageUpdate: ${error.message}` + ); } throw error; } @@ -331,49 +371,60 @@ async function demonstrateMessageUpdate(messageId: string): Promise { */ async function demonstrateScheduledMessages(): Promise { console.log('\n=== Demonstrating Scheduled Messages ==='); - + try { // List scheduled messages console.log('Listing scheduled messages...'); const scheduledMessages = await nylas.messages.listScheduledMessages({ - identifier: grantId + identifier: grantId, }); - + // Handle case where schedules might be undefined or empty const schedules = scheduledMessages.data.schedules || []; console.log(`Found ${schedules.length} scheduled messages`); - + if (schedules.length === 0) { - console.log('No scheduled messages found. This is normal if you haven\'t scheduled any messages.'); + console.log( + "No scheduled messages found. This is normal if you haven't scheduled any messages." + ); return; } - + for (const schedule of schedules) { console.log(`- Schedule ID: ${schedule.scheduleId}`); - console.log(` Status: ${schedule.status.code} - ${schedule.status.description}`); + console.log( + ` Status: ${schedule.status.code} - ${schedule.status.description}` + ); if (schedule.closeTime) { - console.log(` Close Time: ${new Date(schedule.closeTime * 1000).toISOString()}`); + console.log( + ` Close Time: ${new Date(schedule.closeTime * 1000).toISOString()}` + ); } } - + // If there are scheduled messages, demonstrate finding one const firstSchedule = schedules[0]; - console.log(`\nGetting details for scheduled message: ${firstSchedule.scheduleId}`); - + console.log( + `\nGetting details for scheduled message: ${firstSchedule.scheduleId}` + ); + const scheduleDetails = await nylas.messages.findScheduledMessage({ identifier: grantId, - scheduleId: firstSchedule.scheduleId.toString() + scheduleId: firstSchedule.scheduleId.toString(), }); - + console.log('Scheduled message details:'); console.log(`- Schedule ID: ${scheduleDetails.data.scheduleId}`); - console.log(`- Status: ${scheduleDetails.data.status.code} - ${scheduleDetails.data.status.description}`); - + console.log( + `- Status: ${scheduleDetails.data.status.code} - ${scheduleDetails.data.status.description}` + ); } catch (error) { if (error instanceof NylasApiError) { console.error(`Error with scheduled messages: ${error.message}`); } else if (error instanceof Error) { - console.error(`Unexpected error in demonstrateScheduledMessages: ${error.message}`); + console.error( + `Unexpected error in demonstrateScheduledMessages: ${error.message}` + ); } throw error; } @@ -384,54 +435,61 @@ async function demonstrateScheduledMessages(): Promise { */ async function demonstrateMessageCleaning(): Promise { console.log('\n=== Demonstrating Message Cleaning ==='); - + try { // Get a few message IDs for cleaning const messages = await nylas.messages.list({ identifier: grantId, queryParams: { - limit: 2 - } + limit: 2, + }, }); - + if (messages.data.length === 0) { console.log('No messages available for cleaning demonstration'); return; } - - const messageIds = messages.data.map(m => m.id); + + const messageIds = messages.data.map((m) => m.id); console.log(`Cleaning ${messageIds.length} messages...`); - + const cleanRequest: CleanMessagesRequest = { messageId: messageIds, ignoreLinks: true, ignoreImages: true, ignoreTables: false, imagesAsMarkdown: false, - removeConclusionPhrases: true + removeConclusionPhrases: true, }; - + const cleanedMessages = await nylas.messages.cleanMessages({ identifier: grantId, - requestBody: cleanRequest + requestBody: cleanRequest, }); - + console.log(`Successfully cleaned ${cleanedMessages.data.length} messages`); for (const cleanedMessage of cleanedMessages.data) { console.log(`- Message ID: ${cleanedMessage.id}`); - console.log(` Original body length: ${cleanedMessage.body?.length || 0} characters`); - console.log(` Cleaned conversation length: ${cleanedMessage.conversation?.length || 0} characters`); + console.log( + ` Original body length: ${cleanedMessage.body?.length || 0} characters` + ); + console.log( + ` Cleaned conversation length: ${cleanedMessage.conversation?.length || 0} characters` + ); if (cleanedMessage.conversation) { const preview = cleanedMessage.conversation.substring(0, 100); - console.log(` Cleaned preview: ${preview}${cleanedMessage.conversation.length > 100 ? '...' : ''}`); + console.log( + ` Cleaned preview: ${preview}${cleanedMessage.conversation.length > 100 ? '...' : ''}` + ); } } - } catch (error) { if (error instanceof NylasApiError) { console.error(`Error cleaning messages: ${error.message}`); } else if (error instanceof Error) { - console.error(`Unexpected error in demonstrateMessageCleaning: ${error.message}`); + console.error( + `Unexpected error in demonstrateMessageCleaning: ${error.message}` + ); } throw error; } @@ -442,7 +500,7 @@ async function demonstrateMessageCleaning(): Promise { */ async function demonstrateMessageQuerying(): Promise { console.log('\n=== Demonstrating Message Querying ==='); - + try { // Query recent unread messages console.log('\n--- Finding recent unread messages ---'); @@ -451,43 +509,50 @@ async function demonstrateMessageQuerying(): Promise { queryParams: { unread: true, limit: 5, - fields: MessageFields.INCLUDE_TRACKING_OPTIONS - } + fields: MessageFields.INCLUDE_TRACKING_OPTIONS, + }, }); - + console.log(`Found ${unreadMessages.data.length} unread messages`); for (const message of unreadMessages.data) { console.log(`- ${message.id}: ${message.subject || '(no subject)'}`); console.log(` Date: ${new Date(message.date * 1000).toISOString()}`); - console.log(` From: ${message.from?.map(f => `${f.name} <${f.email}>`).join(', ') || 'Unknown'}`); + console.log( + ` From: ${message.from?.map((f) => `${f.name} <${f.email}>`).join(', ') || 'Unknown'}` + ); } - + // Query messages with attachments console.log('\n--- Finding messages with attachments ---'); const attachmentMessages = await nylas.messages.list({ identifier: grantId, queryParams: { hasAttachment: true, - limit: 3 - } + limit: 3, + }, }); - - console.log(`Found ${attachmentMessages.data.length} messages with attachments`); + + console.log( + `Found ${attachmentMessages.data.length} messages with attachments` + ); for (const message of attachmentMessages.data) { console.log(`- ${message.id}: ${message.subject || '(no subject)'}`); console.log(` Attachments: ${message.attachments?.length || 0}`); if (message.attachments && message.attachments.length > 0) { - message.attachments.forEach(att => { - console.log(` - ${att.filename} (${att.contentType}, ${att.size} bytes)`); + message.attachments.forEach((att) => { + console.log( + ` - ${att.filename} (${att.contentType}, ${att.size} bytes)` + ); }); } } - } catch (error) { if (error instanceof NylasApiError) { console.error(`Error querying messages: ${error.message}`); } else if (error instanceof Error) { - console.error(`Unexpected error in demonstrateMessageQuerying: ${error.message}`); + console.error( + `Unexpected error in demonstrateMessageQuerying: ${error.message}` + ); } throw error; } @@ -501,27 +566,28 @@ async function main(): Promise { console.log('=== Nylas Messages API Examples ==='); console.log(`API Key: ${apiKey.substring(0, 8)}...`); console.log(`Grant ID: ${grantId}`); - console.log(`API URI: ${process.env.NYLAS_API_URI || 'https://api.us.nylas.com'}`); - + console.log( + `API URI: ${process.env.NYLAS_API_URI || 'https://api.us.nylas.com'}` + ); + // Run all demonstrations await demonstrateMessageFields(); await demonstratePlaintextMessageSending(); await demonstrateRawMime(); await demonstrateMessageQuerying(); - + // Send a message if TEST_EMAIL is provided const sentMessage = await demonstrateMessageSending(); - + // If we sent a message, demonstrate updating it if (sentMessage) { await demonstrateMessageUpdate(sentMessage.data.id); } - + await demonstrateScheduledMessages(); await demonstrateMessageCleaning(); - + console.log('\n=== All message examples completed successfully! ==='); - } catch (error) { console.error('\n=== Error running message examples ==='); if (error instanceof NylasApiError) { @@ -541,4 +607,4 @@ async function main(): Promise { // Run the main function if (require.main === module) { main(); -} \ No newline at end of file +} diff --git a/examples/messages/send-attachments-cli.ts b/examples/messages/send-attachments-cli.ts index 50949fe5..b8f91d46 100644 --- a/examples/messages/send-attachments-cli.ts +++ b/examples/messages/send-attachments-cli.ts @@ -10,7 +10,7 @@ import { TestFileManager } from './utils/attachment-file-manager'; // Example 1: File Path Attachments (Most Common & Efficient) import { sendFilePathAttachments } from './examples/file-path-attachments'; -// Example 2: Stream Attachments (For More Control) +// Example 2: Stream Attachments (For More Control) import { sendStreamAttachments } from './examples/stream-attachments'; // Example 3: Buffer Attachments (For Small Files) @@ -26,13 +26,15 @@ import { sendAttachmentsByFormat } from './examples/flexible-attachments'; // šŸ“‚ File Manager - Manage test files // ============================================================================= // Available test files in the examples/messages/attachments directory -const testFileManager = new TestFileManager(path.resolve(__dirname, './attachments'), [ - 'test-small-26B.txt', - 'test-image-512KB.jpg', - 'test-document-12MB.pdf', - 'test-image-10MB.jpg' -]); - +const testFileManager = new TestFileManager( + path.resolve(__dirname, './attachments'), + [ + 'test-small-26B.txt', + 'test-image-512KB.jpg', + 'test-document-12MB.pdf', + 'test-image-10MB.jpg', + ] +); // ============================================================================= // šŸ› ļø CLI Interface - Start CLI when run directly @@ -46,7 +48,7 @@ const sendAttachmentsExamples: SendAttachmentsExamples = { sendStreamAttachments, sendBufferAttachments, sendStringAttachments, - sendAttachmentsByFormat + sendAttachmentsByFormat, }; const grantId: string = process.env.NYLAS_GRANT_ID || ''; @@ -63,8 +65,12 @@ dotenv.config({ path: path.resolve(__dirname, '../.env') }); // Run the CLI if (require.main === module) { - startCli(sendAttachmentsExamples, testFileManager, process.env.TEST_EMAIL || '').catch(error => { + startCli( + sendAttachmentsExamples, + testFileManager, + process.env.TEST_EMAIL || '' + ).catch((error) => { console.error('Error:', error.message); process.exit(1); }); -} \ No newline at end of file +} diff --git a/examples/messages/utils/attachment-file-manager.ts b/examples/messages/utils/attachment-file-manager.ts index 963d492e..9b9c1822 100644 --- a/examples/messages/utils/attachment-file-manager.ts +++ b/examples/messages/utils/attachment-file-manager.ts @@ -3,7 +3,6 @@ import * as fs from 'fs'; import * as mime from 'mime-types'; import { CreateAttachmentRequest } from 'nylas'; - /** * File format types for different ways to handle attachments */ @@ -11,7 +10,7 @@ export type FileFormat = 'file' | 'stream' | 'buffer' | 'string'; /** * Maximum size for small files - */ + */ export const MAX_SMALL_FILE_SIZE_LIMIT = 1024 * 1024 * 3; // 3MB /** @@ -23,7 +22,7 @@ interface FileHandler { filename: string; size: number; contentType: string; - + // Methods to get content in different formats asFileRequest(): CreateAttachmentRequest; asStream(): fs.ReadStream; @@ -47,7 +46,7 @@ export class TestFileHandler implements FileHandler { this.path = path.resolve(attachmentsDir, fileName); this.exists = fs.existsSync(this.path); this.filename = path.basename(this.path); - + if (this.exists) { const stats = fs.statSync(this.path); this.size = stats.size; @@ -101,15 +100,20 @@ export class TestFileHandler implements FileHandler { if (!this.exists) { throw new Error(`File not found: ${this.filename}`); } - + // Check if it's likely a text file const textTypes = ['text/', 'application/json', 'application/xml']; - const isTextFile = textTypes.some(type => this.contentType.startsWith(type)); - - if (!isTextFile && this.size > MAX_SMALL_FILE_SIZE_LIMIT) { // > 1MB - throw new Error(`File ${this.filename} is too large or not a text file to read as string`); + const isTextFile = textTypes.some((type) => + this.contentType.startsWith(type) + ); + + if (!isTextFile && this.size > MAX_SMALL_FILE_SIZE_LIMIT) { + // > 1MB + throw new Error( + `File ${this.filename} is too large or not a text file to read as string` + ); } - + return fs.readFileSync(this.path, 'utf8'); } } @@ -124,9 +128,9 @@ export class TestFileManager { constructor(baseDir?: string, files?: string[]) { // Default to attachments subdirectory relative to the messages folder this.baseDir = baseDir || path.resolve(__dirname, '../attachments'); - + // Initialize all test files - files?.forEach(fileName => { + files?.forEach((fileName) => { this.files.set(fileName, new TestFileHandler(fileName, this.baseDir)); }); } @@ -153,21 +157,25 @@ export class TestFileManager { * Get only files that exist */ getExistingFiles(): TestFileHandler[] { - return this.getAllFiles().filter(file => file.exists); + return this.getAllFiles().filter((file) => file.exists); } /** * Get small files (< 1MB) */ getSmallFiles(): TestFileHandler[] { - return this.getExistingFiles().filter(file => file.size < MAX_SMALL_FILE_SIZE_LIMIT); + return this.getExistingFiles().filter( + (file) => file.size < MAX_SMALL_FILE_SIZE_LIMIT + ); } /** * Get large files (>= 1MB) */ getLargeFiles(): TestFileHandler[] { - return this.getExistingFiles().filter(file => file.size >= MAX_SMALL_FILE_SIZE_LIMIT); + return this.getExistingFiles().filter( + (file) => file.size >= MAX_SMALL_FILE_SIZE_LIMIT + ); } /** @@ -175,9 +183,12 @@ export class TestFileManager { */ checkFileStatus(): void { console.log('\nChecking test file status:'); - this.getAllFiles().forEach(file => { - const status = file.exists ? `āœ“ Found (${file.size} bytes)` : 'āœ— Not found'; - const sizeLabel = file.size >= MAX_SMALL_FILE_SIZE_LIMIT ? 'LARGE' : 'SMALL'; + this.getAllFiles().forEach((file) => { + const status = file.exists + ? `āœ“ Found (${file.size} bytes)` + : 'āœ— Not found'; + const sizeLabel = + file.size >= MAX_SMALL_FILE_SIZE_LIMIT ? 'LARGE' : 'SMALL'; console.log(` ${file.filename}: ${status} [${sizeLabel}]`); }); } @@ -185,13 +196,16 @@ export class TestFileManager { /** * Create attachment request for a file in the specified format */ - createAttachmentRequest(fileName: string, format: FileFormat): CreateAttachmentRequest { + createAttachmentRequest( + fileName: string, + format: FileFormat + ): CreateAttachmentRequest { const file = this.getFile(fileName); - + switch (format) { case 'file': return file.asFileRequest(); - + case 'stream': return { filename: file.filename, @@ -199,7 +213,7 @@ export class TestFileManager { content: file.asStream(), size: file.size, }; - + case 'buffer': return { filename: file.filename, @@ -207,7 +221,7 @@ export class TestFileManager { content: file.asBuffer(), size: file.size, }; - + case 'string': const stringContent = file.asString(); return { @@ -216,7 +230,7 @@ export class TestFileManager { content: stringContent, size: Buffer.byteLength(stringContent, 'utf8'), }; - + default: throw new Error(`Unsupported format: ${format}`); } @@ -227,10 +241,12 @@ export class TestFileManager { * Helper function to create a file request builder for any file path * This maintains backward compatibility with the original function */ -export function createFileRequestBuilder(filePath: string): CreateAttachmentRequest { +export function createFileRequestBuilder( + filePath: string +): CreateAttachmentRequest { // If it's not an absolute path, assume it's in the attachments subdirectory const fullPath = path.resolve(__dirname, filePath); - + const stats = fs.statSync(fullPath); const filename = path.basename(fullPath); const contentType = mime.lookup(fullPath) || 'application/octet-stream'; @@ -242,4 +258,4 @@ export function createFileRequestBuilder(filePath: string): CreateAttachmentRequ content, size: stats.size, }; -} \ No newline at end of file +} diff --git a/examples/notetakers/notetaker.ts b/examples/notetakers/notetaker.ts index d16292fd..cc3166fc 100644 --- a/examples/notetakers/notetaker.ts +++ b/examples/notetakers/notetaker.ts @@ -2,15 +2,15 @@ import dotenv from 'dotenv'; import path from 'path'; import * as process from 'process'; import Nylas from 'nylas'; -import { - CreateNotetakerRequest, - NotetakerMedia, - NotetakerLeaveResponse, +import { + CreateNotetakerRequest, + NotetakerMedia, + NotetakerLeaveResponse, Notetaker, - NylasResponse, + NylasResponse, NylasListResponse, NylasApiError, - ListNotetakersQueryParams + ListNotetakersQueryParams, } from 'nylas'; // Load environment variables from .env file @@ -25,7 +25,7 @@ if (!apiKey) { // Initialize the Nylas client const nylas = new Nylas({ apiKey, - apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com' + apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com', }); /** @@ -34,27 +34,29 @@ const nylas = new Nylas({ */ async function inviteNotetaker(): Promise> { console.log('\n=== Inviting Notetaker to Meeting ==='); - + try { const meetingLink: string = process.env.MEETING_LINK || ''; if (!meetingLink) { - throw new Error('MEETING_LINK environment variable is not set. Please set it with your meeting URL.'); + throw new Error( + 'MEETING_LINK environment variable is not set. Please set it with your meeting URL.' + ); } - + const requestBody: CreateNotetakerRequest = { meetingLink, name: 'Nylas Notetaker', meetingSettings: { videoRecording: true, audioRecording: true, - transcription: true - } + transcription: true, + }, }; - + console.log(`Request body: ${JSON.stringify(requestBody, null, 2)}`); - + const notetaker = await nylas.notetakers.create({ requestBody }); - + console.log(`Invited Notetaker with ID: ${notetaker.data.id}`); console.log(`Name: ${notetaker.data.name}`); console.log(`State: ${notetaker.data.state}`); @@ -77,21 +79,25 @@ async function inviteNotetaker(): Promise> { */ async function listNotetakers(): Promise> { console.log('\n=== Listing All Notetakers ==='); - + try { // List notetakers ordered by name in ascending order const notetakers = await nylas.notetakers.list({ queryParams: { orderBy: 'name', - orderDirection: 'asc' - } + orderDirection: 'asc', + }, }); - - console.log(`Found ${notetakers.data.length} notetakers (ordered by name):`); + + console.log( + `Found ${notetakers.data.length} notetakers (ordered by name):` + ); for (const notetaker of notetakers.data) { - console.log(`- ${notetaker.name} (ID: ${notetaker.id}, State: ${notetaker.state})`); + console.log( + `- ${notetaker.name} (ID: ${notetaker.id}, State: ${notetaker.state})` + ); } - + return notetakers; } catch (error) { if (error instanceof NylasApiError) { @@ -108,62 +114,90 @@ async function listNotetakers(): Promise> { * @param notetakerId The ID of the Notetaker to get media from * @returns The media (recording and transcript) from the Notetaker */ -async function getNotetakerMedia(notetakerId: string): Promise> { +async function getNotetakerMedia( + notetakerId: string +): Promise> { console.log('\n=== Getting Notetaker Media ==='); - + try { const media = await nylas.notetakers.downloadMedia({ notetakerId }); - + if (media.data.recording) { const recording = media.data.recording; console.log(`Recording URL: ${recording.url}`); console.log(`Recording Name: ${recording.name}`); console.log(`Recording Type: ${recording.type}`); console.log(`Recording Size: ${recording.size} bytes`); - + // Handle both snake_case (API) and camelCase (SDK model) property naming - const createdAt = 'createdAt' in recording ? recording.createdAt : - 'created_at' in recording ? (recording as any).created_at : undefined; - const expiresAt = 'expiresAt' in recording ? recording.expiresAt : - 'expires_at' in recording ? (recording as any).expires_at : undefined; - + const createdAt = + 'createdAt' in recording + ? recording.createdAt + : 'created_at' in recording + ? (recording as any).created_at + : undefined; + const expiresAt = + 'expiresAt' in recording + ? recording.expiresAt + : 'expires_at' in recording + ? (recording as any).expires_at + : undefined; + if (createdAt) { - console.log(`Recording Created: ${new Date(createdAt * 1000).toISOString()}`); + console.log( + `Recording Created: ${new Date(createdAt * 1000).toISOString()}` + ); } if (expiresAt) { - console.log(`Recording Expires: ${new Date(expiresAt * 1000).toISOString()}`); + console.log( + `Recording Expires: ${new Date(expiresAt * 1000).toISOString()}` + ); } console.log(`Recording TTL: ${recording.ttl} seconds`); } - + if (media.data.transcript) { const transcript = media.data.transcript; console.log(`Transcript URL: ${transcript.url}`); console.log(`Transcript Name: ${transcript.name}`); console.log(`Transcript Type: ${transcript.type}`); console.log(`Transcript Size: ${transcript.size} bytes`); - + // Handle both snake_case (API) and camelCase (SDK model) property naming - const createdAt = 'createdAt' in transcript ? transcript.createdAt : - 'created_at' in transcript ? (transcript as any).created_at : undefined; - const expiresAt = 'expiresAt' in transcript ? transcript.expiresAt : - 'expires_at' in transcript ? (transcript as any).expires_at : undefined; - + const createdAt = + 'createdAt' in transcript + ? transcript.createdAt + : 'created_at' in transcript + ? (transcript as any).created_at + : undefined; + const expiresAt = + 'expiresAt' in transcript + ? transcript.expiresAt + : 'expires_at' in transcript + ? (transcript as any).expires_at + : undefined; + if (createdAt) { - console.log(`Transcript Created: ${new Date(createdAt * 1000).toISOString()}`); + console.log( + `Transcript Created: ${new Date(createdAt * 1000).toISOString()}` + ); } if (expiresAt) { - console.log(`Transcript Expires: ${new Date(expiresAt * 1000).toISOString()}`); + console.log( + `Transcript Expires: ${new Date(expiresAt * 1000).toISOString()}` + ); } console.log(`Transcript TTL: ${transcript.ttl} seconds`); } - + return media; } catch (error) { if (error instanceof NylasApiError) { console.error(`Error getting notetaker media: ${error.message}`); } else if (error instanceof Error) { - console.error(`Unexpected error in get_notetaker_media: ${error.message}`); + console.error( + `Unexpected error in get_notetaker_media: ${error.message}` + ); } throw error; } @@ -174,9 +208,11 @@ async function getNotetakerMedia(notetakerId: string): Promise> { +async function leaveNotetaker( + notetakerId: string +): Promise> { console.log('\n=== Leaving Notetaker ==='); - + try { const response = await nylas.notetakers.leave({ notetakerId }); console.log(`Left Notetaker with ID: ${response.data.id}`); @@ -199,24 +235,27 @@ async function main(): Promise { try { // Log API key (first few characters only) console.log(`Using API key: ${apiKey.substring(0, 5)}...`); - + // Invite a Notetaker to a meeting const notetaker = await inviteNotetaker(); - + // List all Notetakers await listNotetakers(); - + // Get media from the Notetaker (if available) if (notetaker.data.state === 'media_available') { await getNotetakerMedia(notetaker.data.id); } else { - console.log(`\nNotetaker state is ${notetaker.data.state}, media not available yet.`); - console.log(`You can check back later when the state is 'media_available'.`); + console.log( + `\nNotetaker state is ${notetaker.data.state}, media not available yet.` + ); + console.log( + `You can check back later when the state is 'media_available'.` + ); } - + // Leave the Notetaker meeting await leaveNotetaker(notetaker.data.id); - } catch (error) { if (error instanceof NylasApiError) { console.error(`\nNylas API Error: ${error.message}`); @@ -233,4 +272,4 @@ async function main(): Promise { // Run the main function if (require.main === module) { main().catch(console.error); -} \ No newline at end of file +} diff --git a/examples/package-lock.json b/examples/package-lock.json index 873702b8..1684f867 100644 --- a/examples/package-lock.json +++ b/examples/package-lock.json @@ -8,31 +8,31 @@ "name": "nylas-examples", "version": "1.0.0", "dependencies": { - "chalk": "^5.3.0", - "commander": "^11.1.0", - "dotenv": "^16.0.0", - "inquirer": "^9.2.12", - "mime-types": "^2.1.35", + "chalk": "^5.6.2", + "commander": "^14.0.0", + "dotenv": "^17.2.2", + "inquirer": "^12.9.4", + "mime-types": "^3.0.1", "nylas": "file:.." }, "devDependencies": { - "@types/inquirer": "^9.0.7", + "@types/inquirer": "^9.0.9", "@types/mime-types": "^2.1.4", "@types/node": "^18.11.9", - "ts-node": "^10.8.0", - "typescript": "^5.0.0" + "ts-node": "^10.9.2", + "typescript": "^5.8.3" } }, "..": { "name": "nylas", - "version": "7.11.0", + "version": "7.13.0", "license": "MIT", "dependencies": { "change-case": "^4.1.2", "form-data-encoder": "^4.1.0", "formdata-node": "^6.0.3", "mime-types": "^2.1.35", - "node-fetch": "^2.6.12", + "node-fetch": "^3.3.2", "uuid": "^8.3.2" }, "devDependencies": { @@ -40,7 +40,6 @@ "@types/jest": "^29.5.2", "@types/mime-types": "^2.1.2", "@types/node": "^22.15.21", - "@types/node-fetch": "^2.6.4", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^2.25.0", "@typescript-eslint/parser": "^2.25.0", @@ -50,6 +49,7 @@ "eslint-plugin-import": "^2.28.1", "eslint-plugin-prettier": "^3.0.1", "jest": "^29.6.1", + "jest-fetch-mock": "^3.0.3", "prettier": "^3.5.3", "ts-jest": "^29.1.1", "typedoc": "^0.28.4", @@ -73,13 +73,329 @@ "node": ">=12" } }, + "node_modules/@inquirer/checkbox": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.2.tgz", + "integrity": "sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.16.tgz", + "integrity": "sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", + "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.18", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.18.tgz", + "integrity": "sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/external-editor": "^1.0.1", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.18.tgz", + "integrity": "sha512-xUjteYtavH7HwDMzq4Cn2X4Qsh5NozoDHCJTdoXg9HfZ4w3R6mxV1B9tL7DGJX2eq/zqtsFjhm0/RJIMGlh3ag==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@inquirer/figures": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", - "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.2.tgz", + "integrity": "sha512-hqOvBZj/MhQCpHUuD3MVq18SSoDNHy7wEnQ8mtvs71K8OPZVXJinOzcvQna33dNYLYE4LkA9BlhAhK6MJcsVbw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.18.tgz", + "integrity": "sha512-7exgBm52WXZRczsydCVftozFTrrwbG5ySE0GqUd2zLNSBXyIucs2Wnm7ZKLe/aUu6NUg9dg7Q80QIHCdZJiY4A==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.18.tgz", + "integrity": "sha512-zXvzAGxPQTNk/SbT3carAD4Iqi6A2JS2qtcqQjsL22uvD+JfQzUrDEtPjLL7PLn8zlSNyPdY02IiQjzoL9TStA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.4.tgz", + "integrity": "sha512-MuxVZ1en1g5oGamXV3DWP89GEkdD54alcfhHd7InUW5BifAdKQEK9SLFa/5hlWbvuhMPlobF0WAx7Okq988Jxg==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.2.2", + "@inquirer/confirm": "^5.1.16", + "@inquirer/editor": "^4.2.18", + "@inquirer/expand": "^4.0.18", + "@inquirer/input": "^4.2.2", + "@inquirer/number": "^3.0.18", + "@inquirer/password": "^4.0.18", + "@inquirer/rawlist": "^4.1.6", + "@inquirer/search": "^3.1.1", + "@inquirer/select": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.6.tgz", + "integrity": "sha512-KOZqa3QNr3f0pMnufzL7K+nweFFCCBs6LCXZzXDrVGTyssjLeudn5ySktZYv1XiSqobyHRYYK0c6QsOxJEhXKA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.1.tgz", + "integrity": "sha512-TkMUY+A2p2EYVY3GCTItYGvqT6LiLzHBnqsU1rJbrpXUijFfM6zvUx0R4civofVwFCmJZcKqOVwwWAjplKkhxA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.2.tgz", + "integrity": "sha512-nwous24r31M+WyDEHV+qckXkepvihxhnyIaod2MG7eCE6G0Zm/HUF6jgN8GXgf4U7AU6SLseKdanY195cwvU6w==", "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@jridgewell/resolve-uri": { @@ -139,9 +455,9 @@ "license": "MIT" }, "node_modules/@types/inquirer": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.8.tgz", - "integrity": "sha512-CgPD5kFGWsb8HJ5K7rfWlifao87m4ph8uioU7OTncJevmE/VLIqAAjfQtko578JZg7/f69K4FgqYym3gNr7DeA==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.9.tgz", + "integrity": "sha512-/mWx5136gts2Z2e5izdoRCo46lPp5TMs9R15GTSsgg/XnZyxDWVqoVU3R9lWnccKpqwsJLvRoxbCjoJtZB7DSw==", "dev": true, "license": "MIT", "dependencies": { @@ -160,7 +476,7 @@ "version": "18.19.86", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -248,65 +564,10 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -316,35 +577,11 @@ } }, "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", "license": "MIT" }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -354,15 +591,6 @@ "node": ">= 12" } }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -382,12 +610,12 @@ "license": "MIT" }, "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", "license": "MIT", "engines": { - "node": ">=16" + "node": ">=20" } }, "node_modules/create-require": { @@ -397,18 +625,6 @@ "dev": true, "license": "MIT" }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -420,9 +636,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", + "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -437,88 +653,42 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, "node_modules/inquirer": { - "version": "9.3.7", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.7.tgz", - "integrity": "sha512-LJKFHCSeIRq9hanN14IlOtPSTe3lNES7TYDTE2xxdAy1LS5rYphajK1qtwvj3YmQXvvk0U2Vbmcni8P9EIQW9w==", + "version": "12.9.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.9.4.tgz", + "integrity": "sha512-5bV3LOgLtMAiJq1QpaUddfRrvaX59wiMYppS7z2jNRSQ64acI0yqx7WMxWhgymenSXOyD657g9tlsTjqGYM8sg==", "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.3", + "@inquirer/core": "^10.2.0", + "@inquirer/prompts": "^7.8.4", + "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "mute-stream": "^2.0.0", + "run-async": "^4.0.5", + "rxjs": "^7.8.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/is-fullwidth-code-point": { @@ -530,59 +700,6 @@ "node": ">=8" } }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -591,142 +708,43 @@ "license": "ISC" }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/nylas": { "resolved": "..", "link": true }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -741,26 +759,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -768,18 +766,15 @@ "license": "MIT" }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/string-width": { @@ -808,30 +803,6 @@ "node": ">=8" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -912,13 +883,7 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "devOptional": true, "license": "MIT" }, "node_modules/v8-compile-cache-lib": { @@ -928,15 +893,6 @@ "dev": true, "license": "MIT" }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -962,9 +918,9 @@ } }, "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "license": "MIT", "engines": { "node": ">=18" diff --git a/examples/package.json b/examples/package.json index de670a7f..e8d28a31 100644 --- a/examples/package.json +++ b/examples/package.json @@ -13,18 +13,18 @@ "folders": "ts-node folders/folders.ts" }, "dependencies": { - "chalk": "^5.3.0", - "commander": "^11.1.0", - "dotenv": "^16.0.0", - "inquirer": "^9.2.12", - "mime-types": "^2.1.35", + "chalk": "^5.6.2", + "commander": "^14.0.0", + "dotenv": "^17.2.2", + "inquirer": "^12.9.4", + "mime-types": "^3.0.1", "nylas": "file:.." }, "devDependencies": { - "ts-node": "^10.8.0", - "typescript": "^5.0.0", + "ts-node": "^10.9.2", + "typescript": "^5.8.3", "@types/node": "^18.11.9", - "@types/inquirer": "^9.0.7", + "@types/inquirer": "^9.0.9", "@types/mime-types": "^2.1.4" } } \ No newline at end of file diff --git a/examples/utils/logger.mjs b/examples/utils/logger.mjs new file mode 100644 index 00000000..758eb4c2 --- /dev/null +++ b/examples/utils/logger.mjs @@ -0,0 +1,44 @@ +// Pretty logger +const COLORS = { + reset: '\x1b[0m', + dim: '\x1b[2m', + gray: '\x1b[90m', + bold: '\x1b[1m', + info: '\x1b[36m', + success: '\x1b[32m', + warn: '\x1b[33m', + error: '\x1b[31m', + debug: '\x1b[35m', +}; + +export function ts() { + return new Date().toISOString(); +} + +export function maskSecret(value, visibleStart = 8, visibleEnd = 0) { + if (!value) return ''; + const start = value.slice(0, visibleStart); + const end = visibleEnd ? value.slice(-visibleEnd) : ''; + const hidden = Math.max(0, value.length - start.length - end.length); + return `${start}${'•'.repeat(hidden)}${end}`; +} + +export function print(level, symbol, message, meta) { + const color = COLORS[level] || COLORS.info; + const time = `${COLORS.dim}${ts()}${COLORS.reset}`; + const label = `${color}${symbol} ${level.toUpperCase()}${COLORS.reset}`; + const line = + typeof message === 'string' ? message : JSON.stringify(message, null, 2); + console.log(`${time} ${label} ${line}`); + if (meta !== undefined) { + console.dir(meta, { depth: null, colors: true, maxArrayLength: 100 }); + } +} + +export const logger = { + info: (msg, meta) => print('info', 'ℹ', msg, meta), + success: (msg, meta) => print('success', 'āœ”', msg, meta), + warn: (msg, meta) => print('warn', '⚠', msg, meta), + error: (msg, meta) => print('error', 'āœ–', msg, meta), + debug: (msg, meta) => print('debug', 'šŸ›', msg, meta), +};