Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/workflows/validate-types.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Sample GitHub Actions workflow for CI/CD validation
# This ensures that tests pass and builds are successful

name: Validate and Build

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]

jobs:
validate:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16.x, 18.x, 20.x]

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci



- name: Run linting
run: npm run lint:ci

- name: Run tests
run: npm test

- name: Build project
run: npm run build

- name: Run test coverage
run: npm run test:coverage

- name: Validate examples (if they exist)
run: |
if [ -d "examples" ]; then
cd examples
npm install
npx tsc --noEmit
else
echo "No examples directory found, skipping validation"
fi

# Optional: Run full release validation on main branch
validate-release:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
needs: validate

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20.x'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run full release validation
run: npm run validate-release
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Support for dedicated types export via `nylas/types` subpath for third-party developers building extensions

## [7.11.0] - 2025-06-23

### Added
Expand Down
4 changes: 2 additions & 2 deletions examples/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"compilerOptions": {
"target": "es2019",
"module": "commonjs",
"module": "Node16",
"lib": ["es2019", "dom"],
"declaration": false,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"moduleResolution": "node16",
"resolveJsonModule": true,
"outDir": "dist"
},
Expand Down
14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@
"export-version": "node scripts/exportVersion.js",
"generate-lib-package-json": "node scripts/generateLibPackageJson.js",
"generate-model-index": "node scripts/generateModelIndex.js",
"generate-types-via-api-extractor": "node scripts/generateTypesViaApiExtractor.js",
"validate-release": "node scripts/validateRelease.js",
"prebuild": "npm run export-version && npm run generate-model-index",
"build": "rm -rf lib && npm run build-esm && npm run build-cjs && npm run generate-lib-package-json",
"build-esm": "tsc -p tsconfig.esm.json",
"build-cjs": "tsc -p tsconfig.cjs.json",
"prepare": "npm run build",
"build:docs": "typedoc --out docs",
"version": "npm run export-version && git add src/version.ts"
"preversion": "npm run validate-release",
"version": "npm run export-version && git add src/version.ts",
"postversion": "npm run build && echo 'Post-version build successful'"
},
"keywords": [
"email",
Expand Down Expand Up @@ -71,8 +75,10 @@
"url": "https://github.com/nylas/nylas-nodejs.git"
},
"exports": {
"import": "./lib/esm/nylas.js",
"require": "./lib/cjs/nylas.js",
"types": "./lib/types/nylas.d.ts"
".": {
"import": "./lib/esm/nylas.js",
"require": "./lib/cjs/nylas.js",
"types": "./lib/types/nylas.d.ts"
}
}
}
232 changes: 232 additions & 0 deletions scripts/generateTypesViaApiExtractor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

/**
* Alternative types generation using Microsoft API Extractor
* This generates types.d.ts using the TypeScript compiler and API Extractor
* instead of manual regex parsing
*/

const COLORS = {
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
reset: '\x1b[0m'
};

function log(message, color = 'reset') {
console.log(`${COLORS[color]}${message}${COLORS.reset}`); // eslint-disable-line no-console
}

function createApiExtractorConfig() {
const configPath = path.join(__dirname, '..', 'api-extractor.json');

const config = {
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"mainEntryPointFilePath": "<projectFolder>/lib/types/types.d.ts",
"bundledPackages": [],
"compiler": {
"tsconfigFilePath": "<projectFolder>/tsconfig.json"
},
"apiReport": {
"enabled": false
},
"docModel": {
"enabled": false
},
"dtsRollup": {
"enabled": true,
"untrimmedFilePath": "<projectFolder>/dist/types.d.ts",
"publicTrimmedFilePath": "<projectFolder>/dist/types-public.d.ts"
},
"tsdocMetadata": {
"enabled": false
},
"messages": {
"compilerMessageReporting": {
"default": {
"logLevel": "warning"
}
},
"extractorMessageReporting": {
"default": {
"logLevel": "warning"
}
},
"tsdocMessageReporting": {
"default": {
"logLevel": "warning"
}
}
}
};

fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
log(`✅ Created API Extractor config: ${configPath}`, 'green');
}

function createTypesEntryPoint() {
// Create a comprehensive types entry point for API Extractor to analyze
const typesEntryContent = `/**
* Public API types for third-party developers.
* This file serves as the main entry point for API Extractor.
*
* @public
*/

// Configuration types
export type {
NylasConfig,
OverridableNylasConfig,
Overrides,
Region,
} from '../config.js';

/**
* Configuration constants for different regions
* @public
*/
export {
REGION_CONFIG,
DEFAULT_SERVER_URL,
DEFAULT_REGION,
} from '../config.js';

// Base classes and interfaces
export type { AsyncListResponse } from '../resources/resource.js';

/**
* Base Resource class for extending Nylas SDK functionality
* @public
*/
export { Resource } from '../resources/resource.js';

export type { default as APIClient } from '../apiClient.js';

// Export enum values that need to be used at runtime
export { WhenType } from '../models/events.js';

// APIClient types
export type { RequestOptionsParams } from '../apiClient.js';
export { FLOW_ID_HEADER, REQUEST_ID_HEADER } from '../apiClient.js';

// Response types
export type {
NylasResponse,
NylasListResponse,
NylasBaseResponse,
ListResponseInnerType,
} from '../models/response.js';

// Common query parameter types
export type { ListQueryParams } from '../models/listQueryParams.js';

// Error types
export type {
AbstractNylasApiError,
AbstractNylasSdkError,
NylasApiError,
NylasOAuthError,
NylasSdkTimeoutError,
NylasApiErrorResponse,
NylasApiErrorResponseData,
NylasOAuthErrorResponse,
} from '../models/error.js';

// Utility constants
export { SDK_VERSION } from '../version.js';

// All model types
export * from '../models/index.js';

// Resource parameter interfaces - auto-generated exports
// These would be automatically included by API Extractor
`;

const entryPointPath = path.join(__dirname, '..', 'src', 'typesEntry.ts');
fs.writeFileSync(entryPointPath, typesEntryContent);
log(`✅ Created types entry point: ${entryPointPath}`, 'green');
}

function runApiExtractor() {
log('🔍 Running API Extractor...', 'blue');

try {
// First, ensure we have a clean build
execSync('npm run build', { stdio: 'pipe' });

// Check if API Extractor is installed
try {
execSync('npx api-extractor --version', { stdio: 'pipe' });
} catch (error) {
log('⚠️ API Extractor not installed. To try this approach:', 'yellow');
log(' npm install -D @microsoft/api-extractor', 'yellow');
return;
}

// Run API Extractor
execSync('npx api-extractor run --local', {
encoding: 'utf8',
stdio: 'pipe'
});

log('✅ API Extractor completed successfully', 'green');

// Check if output files were created
const outputFiles = [
'dist/types.d.ts',
'dist/types-public.d.ts'
];

outputFiles.forEach(file => {
const filePath = path.join(__dirname, '..', file);
if (fs.existsSync(filePath)) {
const size = fs.statSync(filePath).size;
log(`📄 Generated: ${file} (${size} bytes)`, 'green');
}
});

} catch (error) {
log('❌ API Extractor failed:', 'red');
log(error.stdout || error.message, 'red');
throw error;
}
}

function generateTypesWithApiExtractor() {
log('🚀 Generating types using API Extractor...', 'blue');

try {
// Step 1: Create API Extractor configuration
createApiExtractorConfig();

// Step 2: Create types entry point
createTypesEntryPoint();

// Step 3: Run API Extractor
runApiExtractor();

log('🎉 Types generation completed!', 'green');
log('', 'reset');
log('Generated files:', 'blue');
log(' - dist/types.d.ts (complete API)', 'green');
log(' - dist/types-public.d.ts (public API only)', 'green');
log('', 'reset');
log('Benefits of this approach:', 'blue');
log(' ✅ Uses TypeScript compiler (100% accurate)', 'green');
log(' ✅ Automatic type extraction', 'green');
log(' ✅ Industry standard tooling', 'green');
log(' ✅ Can trim @internal/@beta APIs', 'green');
log(' ✅ Generates API reports for reviews', 'green');

} catch (error) {
log('💥 Types generation failed!', 'red');
throw error;
}
}

if (require.main === module) {
generateTypesWithApiExtractor();
}
Loading
Loading