Skip to content

Commit d40af03

Browse files
committed
fix: resolve CJS build issue causing "TypeError: Nylas is not a constructor" error
1 parent bc4bbb0 commit d40af03

File tree

8 files changed

+275
-2
lines changed

8 files changed

+275
-2
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Fixed
11+
- Broken CJS build outputs resulted in a "TypeError: Nylas is not a constructor" error
12+
813
## [7.13.0] - 2025-09-01
914

1015
### Added

examples/cjs-only/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# CommonJS-Only Nylas SDK Example
2+
3+
This example demonstrates how to use the Nylas Node.js SDK in a pure CommonJS (CJS) environment without ES module syntax.
4+
5+
## Purpose
6+
7+
- Shows CommonJS `require()` syntax with the Nylas SDK
8+
- Demonstrates environment variable handling in CommonJS
9+
- Provides a simple messages listing example
10+
- Serves as a reference for projects that must use CommonJS
11+
12+
## Key Differences from ESM
13+
14+
This example showcases the CommonJS equivalent of the ESM-only example:
15+
16+
| ESM Syntax | CommonJS Syntax |
17+
|------------|-----------------|
18+
| `import Nylas from 'nylas'` | `const Nylas = require('nylas')` |
19+
| `import dotenv from 'dotenv'` | `const dotenv = require('dotenv')` |
20+
| `import path from 'node:path'` | `const path = require('path')` |
21+
| `import.meta.dirname` | `__dirname` |
22+
| `export { logger }` | `module.exports = { logger }` |
23+
24+
## Setup
25+
26+
1. **Install dependencies:**
27+
```bash
28+
cd examples/cjs-only
29+
npm install
30+
```
31+
32+
2. **Set up environment variables:**
33+
- Copy `examples/.env.example` to `examples/.env`
34+
- Fill in your `NYLAS_API_KEY` and `NYLAS_GRANT_ID`
35+
36+
3. **Run the example:**
37+
```bash
38+
npm start
39+
# or
40+
node index.js
41+
```
42+
43+
## Requirements
44+
45+
- Node.js (any version - CommonJS is supported in all Node.js versions)
46+
- Valid Nylas API credentials
47+
- A grant with message access permissions
48+
49+
## What This Example Does
50+
51+
1. Loads environment variables using `dotenv`
52+
2. Validates required API credentials
53+
3. Initializes the Nylas client
54+
4. Lists messages from the specified grant
55+
5. Logs the results with proper error handling
56+
57+
## File Structure
58+
59+
```
60+
cjs-only/
61+
├── index.js # Main example file (CommonJS)
62+
├── package.json # Package configuration (no "type": "module")
63+
├── utils/
64+
│ └── logger.js # Logger utility (CommonJS exports)
65+
└── README.md # This file
66+
```
67+
68+
## Troubleshooting
69+
70+
- **"NYLAS_API_KEY environment variable is not set"**: Make sure you've created the `.env` file in the `examples/` directory with your API key
71+
- **"NYLAS_GRANT_ID environment variable is not set"**: Add your grant ID to the `.env` file
72+
- **Module not found errors**: Run `npm install` to install dependencies
73+
- **Permission errors**: Ensure your API key and grant have the necessary permissions to list messages
74+
75+
## Related Examples
76+
77+
- `../esm-only/` - ESM version of this same example
78+
- `../messages/` - More comprehensive message handling examples

examples/cjs-only/index.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* CommonJS-Only Nylas SDK Example
3+
*
4+
* This example demonstrates how to use the Nylas Node.js SDK in a pure CommonJS
5+
* (CJS) environment without ES module syntax.
6+
*
7+
* Purpose:
8+
* - Shows CommonJS require() syntax with the Nylas SDK
9+
* - Demonstrates environment variable handling in CommonJS
10+
* - Provides a simple messages listing example
11+
*
12+
* Usage:
13+
* 1. Copy the parent examples/.env.example to examples/.env
14+
* 2. Fill in your NYLAS_API_KEY and NYLAS_GRANT_ID in the .env file
15+
* 3. Run: node index.js (or npm start)
16+
*
17+
* Requirements:
18+
* - Node.js with CommonJS support (any Node.js version)
19+
* - Valid Nylas API credentials
20+
* - A grant with message access permissions
21+
*/
22+
23+
const dotenv = require('dotenv');
24+
const path = require('path');
25+
const Nylas = require('nylas');
26+
const { logger, maskSecret } = require('./utils/logger.js');
27+
28+
// Load from parent directory since this example lives in a subdirectory
29+
dotenv.config({ path: path.resolve(__dirname, '../.env') });
30+
31+
// Fail fast if credentials are missing to provide clear error messages
32+
const apiKey = process.env.NYLAS_API_KEY || '';
33+
if (!apiKey) {
34+
throw new Error('NYLAS_API_KEY environment variable is not set');
35+
}
36+
37+
const grantId = process.env.NYLAS_GRANT_ID || '';
38+
if (!grantId) {
39+
throw new Error('NYLAS_GRANT_ID environment variable is not set');
40+
}
41+
42+
// Initialize the Nylas client
43+
const nylas = new Nylas({
44+
apiKey,
45+
apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com'
46+
});
47+
48+
49+
/**
50+
* Main function to demonstrate basic Nylas SDK usage in CommonJS environment
51+
*/
52+
async function main() {
53+
try {
54+
logger.info('Listing messages...');
55+
56+
// Log runtime config for debugging without exposing sensitive data
57+
logger.debug('Runtime config', {
58+
apiKey: maskSecret(apiKey),
59+
grantId,
60+
apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com'
61+
});
62+
63+
// Use basic list operation to verify SDK functionality and connectivity
64+
const messages = await nylas.messages.list({
65+
identifier: grantId,
66+
});
67+
68+
logger.success('Messages listed successfully');
69+
70+
// Extract only essential fields to avoid logging sensitive message content
71+
logger.info('Message subjects and ids', messages.data.map(m => ({ id: m.id, subject: m.subject })));
72+
73+
} catch (error) {
74+
logger.error('Failed to list messages');
75+
logger.debug('Error details', error);
76+
// Exit with error code to indicate failure for automation/CI purposes
77+
process.exit(1);
78+
}
79+
}
80+
81+
main();

examples/cjs-only/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "cjs-only",
3+
"version": "1.0.0",
4+
"description": "A CommonJS-only example of the Nylas NodeJS SDK usage",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"start": "node index.js"
9+
},
10+
"author": "",
11+
"license": "ISC",
12+
"dependencies": {
13+
"nylas": "file:../../",
14+
"dotenv": "^17.2.2"
15+
}
16+
}

examples/cjs-only/utils/logger.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Pretty logger for CommonJS
2+
const COLORS = {
3+
reset: '\x1b[0m',
4+
dim: '\x1b[2m',
5+
gray: '\x1b[90m',
6+
bold: '\x1b[1m',
7+
info: '\x1b[36m',
8+
success: '\x1b[32m',
9+
warn: '\x1b[33m',
10+
error: '\x1b[31m',
11+
debug: '\x1b[35m',
12+
};
13+
14+
function ts() {
15+
return new Date().toISOString();
16+
}
17+
18+
function maskSecret(value, visibleStart = 8, visibleEnd = 0) {
19+
if (!value) return '';
20+
const start = value.slice(0, visibleStart);
21+
const end = visibleEnd ? value.slice(-visibleEnd) : '';
22+
const hidden = Math.max(0, value.length - start.length - end.length);
23+
return `${start}${'•'.repeat(hidden)}${end}`;
24+
}
25+
26+
function print(level, symbol, message, meta) {
27+
const color = COLORS[level] || COLORS.info;
28+
const time = `${COLORS.dim}${ts()}${COLORS.reset}`;
29+
const label = `${color}${symbol} ${level.toUpperCase()}${COLORS.reset}`;
30+
const line =
31+
typeof message === 'string' ? message : JSON.stringify(message, null, 2);
32+
console.log(`${time} ${label} ${line}`);
33+
if (meta !== undefined) {
34+
console.dir(meta, { depth: null, colors: true, maxArrayLength: 100 });
35+
}
36+
}
37+
38+
const logger = {
39+
info: (msg, meta) => print('info', 'ℹ', msg, meta),
40+
success: (msg, meta) => print('success', '✔', msg, meta),
41+
warn: (msg, meta) => print('warn', '⚠', msg, meta),
42+
error: (msg, meta) => print('error', '✖', msg, meta),
43+
debug: (msg, meta) => print('debug', '🐛', msg, meta),
44+
};
45+
46+
module.exports = { logger, maskSecret };

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
"lint:prettier:check": "prettier --check '**/*.{ts,js}'",
2222
"export-version": "node scripts/exportVersion.js",
2323
"generate-lib-package-json": "node scripts/generateLibPackageJson.js",
24+
"fix-cjs-exports": "node scripts/fixCjsExports.js",
2425
"generate-model-index": "node scripts/generateModelIndex.js",
2526
"prebuild": "npm run export-version && npm run generate-model-index",
26-
"build": "rm -rf lib && npm run build-esm && npm run build-cjs && npm run generate-lib-package-json",
27+
"build": "rm -rf lib && npm run build-esm && npm run build-cjs && npm run generate-lib-package-json && npm run fix-cjs-exports",
2728
"build-esm": "tsc -p tsconfig.esm.json",
2829
"build-cjs": "tsc -p tsconfig.cjs.json",
2930
"prepare": "npm run build",

scripts/fixCjsExports.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* This script fixes the CJS exports to make the Nylas class directly accessible
3+
* via require('nylas') instead of requiring require('nylas').default
4+
*/
5+
6+
const fs = require('fs');
7+
const path = require('path');
8+
9+
// Path to the CJS nylas.js file
10+
const cjsNylasPath = path.join(__dirname, '..', 'lib', 'cjs', 'nylas.js');
11+
12+
// Check if the file exists
13+
if (!fs.existsSync(cjsNylasPath)) {
14+
console.error('CJS nylas.js file not found at:', cjsNylasPath);
15+
process.exit(1);
16+
}
17+
18+
// Read the current content
19+
let content = fs.readFileSync(cjsNylasPath, 'utf8');
20+
21+
// Check if we've already applied the fix
22+
if (content.includes('// CJS compatibility fix applied')) {
23+
console.log('CJS exports fix already applied');
24+
process.exit(0);
25+
}
26+
27+
// Add the CJS compatibility fix
28+
const fixCode = `
29+
// CJS compatibility fix applied
30+
// Support CommonJS require('nylas') directly
31+
module.exports = Nylas;
32+
// Preserve named exports for backward compatibility
33+
Object.assign(module.exports, exports);`;
34+
35+
// Insert the fix before the final closing of the file
36+
content = content.replace(
37+
/exports\.default = Nylas;$/m,
38+
`exports.default = Nylas;${fixCode}`
39+
);
40+
41+
// Write the modified content back
42+
fs.writeFileSync(cjsNylasPath, content);
43+
44+
console.log('CJS exports fix applied successfully');

src/nylas.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Notetakers } from './resources/notetakers.js';
2424
* A Nylas instance holds a configured http client pointing to a base URL and is intended to be reused and shared
2525
* across threads and time.
2626
*/
27-
export default class Nylas {
27+
class Nylas {
2828
/**
2929
* Access the Applications API
3030
*/
@@ -122,3 +122,5 @@ export default class Nylas {
122122
return this;
123123
}
124124
}
125+
126+
export default Nylas;

0 commit comments

Comments
 (0)