tessl install github:jeremylongshore/claude-code-plugins-plus-skills --skill evernote-upgrade-migrationUpgrade Evernote SDK versions and migrate between API versions. Use when upgrading SDK, handling breaking changes, or migrating to newer API patterns. Trigger with phrases like "upgrade evernote sdk", "evernote migration", "update evernote", "evernote breaking changes".
Review Score
84%
Validation Score
12/16
Implementation Score
77%
Activation Score
90%
Guide for upgrading Evernote SDK versions, handling breaking changes, and migrating legacy integrations to current API patterns.
| Version | Node.js | Key Changes |
|---|---|---|
| 2.0.x | 10+ | Promise-based API, ES6 modules |
| 1.25.x | 8+ | Legacy callback pattern |
| 1.x | 6+ | Original SDK |
# Check installed version
npm list evernote
# Check available versions
npm view evernote versions
# Check for outdated packages
npm outdated evernote// SDK 1.x -> 2.x Breaking Changes
// 1. Client initialization changed
// OLD (1.x):
var Evernote = require('evernote').Evernote;
var client = new Evernote.Client({
consumerKey: 'key',
consumerSecret: 'secret',
sandbox: true
});
// NEW (2.x):
const Evernote = require('evernote');
const client = new Evernote.Client({
consumerKey: 'key',
consumerSecret: 'secret',
sandbox: true
});
// 2. API calls return Promises (not callbacks)
// OLD (1.x):
noteStore.listNotebooks(function(err, notebooks) {
if (err) console.error(err);
else console.log(notebooks);
});
// NEW (2.x):
noteStore.listNotebooks()
.then(notebooks => console.log(notebooks))
.catch(err => console.error(err));
// Or with async/await:
const notebooks = await noteStore.listNotebooks();
// 3. Type constructors
// OLD (1.x):
var note = new Evernote.Note();
// NEW (2.x):
const note = new Evernote.Types.Note();// scripts/migrate-to-v2.js
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const migrations = [
// Client import
{
pattern: /require\(['"]evernote['"]\)\.Evernote/g,
replacement: "require('evernote')"
},
// Type constructors
{
pattern: /new Evernote\.Note\(\)/g,
replacement: 'new Evernote.Types.Note()'
},
{
pattern: /new Evernote\.Notebook\(\)/g,
replacement: 'new Evernote.Types.Notebook()'
},
{
pattern: /new Evernote\.Tag\(\)/g,
replacement: 'new Evernote.Types.Tag()'
},
{
pattern: /new Evernote\.Resource\(\)/g,
replacement: 'new Evernote.Types.Resource()'
},
// NoteFilter
{
pattern: /new Evernote\.NoteFilter\(\)/g,
replacement: 'new Evernote.NoteStore.NoteFilter()'
},
// NotesMetadataResultSpec
{
pattern: /new Evernote\.NotesMetadataResultSpec\(\)/g,
replacement: 'new Evernote.NoteStore.NotesMetadataResultSpec()'
}
];
function migrateFile(filePath) {
let content = fs.readFileSync(filePath, 'utf8');
let modified = false;
for (const { pattern, replacement } of migrations) {
if (pattern.test(content)) {
content = content.replace(pattern, replacement);
modified = true;
}
}
if (modified) {
// Create backup
fs.writeFileSync(`${filePath}.bak`, fs.readFileSync(filePath));
// Write migrated file
fs.writeFileSync(filePath, content);
console.log(`Migrated: ${filePath}`);
return true;
}
return false;
}
// Run migration
const files = glob.sync('src/**/*.js');
let migratedCount = 0;
for (const file of files) {
if (migrateFile(file)) {
migratedCount++;
}
}
console.log(`\nMigration complete. ${migratedCount} files modified.`);
console.log('Backup files created with .bak extension');// utils/promisify-legacy.js
/**
* Wrapper for legacy callback-based code
*/
function promisifyNoteStore(noteStore) {
const promisified = {};
// List of methods that need promisification
const methods = [
'listNotebooks',
'getNotebook',
'createNotebook',
'updateNotebook',
'listTags',
'getTag',
'createTag',
'getNote',
'createNote',
'updateNote',
'deleteNote',
'findNotesMetadata',
'getNoteContent',
'getResource'
];
for (const method of methods) {
promisified[method] = (...args) => {
return new Promise((resolve, reject) => {
noteStore[method](...args, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
};
}
return promisified;
}
module.exports = { promisifyNoteStore };# Update to latest version
npm install evernote@latest
# If using TypeScript, update types
npm install @types/evernote@latest --save-dev
# Update related dependencies
npm update// tests/migration-tests.js
const assert = require('assert');
const Evernote = require('evernote');
describe('SDK v2 Migration Tests', () => {
let client;
let noteStore;
before(() => {
client = new Evernote.Client({
token: process.env.EVERNOTE_ACCESS_TOKEN,
sandbox: true
});
noteStore = client.getNoteStore();
});
describe('Type Constructors', () => {
it('should create Note using Types namespace', () => {
const note = new Evernote.Types.Note();
assert(note);
note.title = 'Test';
assert.equal(note.title, 'Test');
});
it('should create NoteFilter using NoteStore namespace', () => {
const filter = new Evernote.NoteStore.NoteFilter({
words: 'test'
});
assert(filter);
assert.equal(filter.words, 'test');
});
});
describe('Promise-based API', () => {
it('should return Promise from listNotebooks', async () => {
const result = noteStore.listNotebooks();
assert(result instanceof Promise);
});
it('should resolve notebooks array', async () => {
const notebooks = await noteStore.listNotebooks();
assert(Array.isArray(notebooks));
});
});
describe('Error Handling', () => {
it('should reject with EDAMUserException for invalid data', async () => {
const note = new Evernote.Types.Note();
// Missing required fields
try {
await noteStore.createNote(note);
assert.fail('Should have thrown');
} catch (error) {
assert(error.errorCode !== undefined);
}
});
});
});// utils/compatibility.js
/**
* Compatibility layer for gradual migration
* Supports both callback and Promise patterns
*/
class CompatibleNoteStore {
constructor(noteStore) {
this.store = noteStore;
}
listNotebooks(callback) {
const promise = this.store.listNotebooks();
if (callback) {
// Legacy callback support
promise
.then(result => callback(null, result))
.catch(error => callback(error, null));
return;
}
return promise;
}
getNote(guid, withContent, withResources, withRecognition, withAlternate, callback) {
const promise = this.store.getNote(
guid,
withContent,
withResources,
withRecognition,
withAlternate
);
if (callback) {
promise
.then(result => callback(null, result))
.catch(error => callback(error, null));
return;
}
return promise;
}
createNote(note, callback) {
const promise = this.store.createNote(note);
if (callback) {
promise
.then(result => callback(null, result))
.catch(error => callback(error, null));
return;
}
return promise;
}
// Add more methods as needed
}
module.exports = CompatibleNoteStore;// utils/deprecation-warnings.js
const deprecations = new Set();
function warnOnce(message) {
if (!deprecations.has(message)) {
deprecations.add(message);
console.warn(`[DEPRECATION WARNING] ${message}`);
}
}
// Proxy to add deprecation warnings
function wrapWithDeprecationWarnings(noteStore) {
return new Proxy(noteStore, {
get(target, prop) {
// Warn about deprecated patterns
if (prop === 'getNote') {
return (...args) => {
if (args.length === 6 && typeof args[5] === 'function') {
warnOnce(
'Callback pattern is deprecated. ' +
'Use Promise: noteStore.getNote(...).then(note => ...)'
);
}
return target[prop](...args);
};
}
return target[prop];
}
});
}
module.exports = { wrapWithDeprecationWarnings };## SDK v2 Migration Checklist
### Pre-Migration
- [ ] Backup current codebase
- [ ] Document current SDK version
- [ ] Review breaking changes
- [ ] Set up test environment
### Code Changes
- [ ] Update import statements
- [ ] Update type constructors (Types namespace)
- [ ] Update filter constructors (NoteStore namespace)
- [ ] Convert callbacks to Promises/async-await
- [ ] Update error handling for Promise rejections
### Testing
- [ ] Run migration script on test branch
- [ ] Execute full test suite
- [ ] Test OAuth flow end-to-end
- [ ] Test note CRUD operations
- [ ] Test search functionality
- [ ] Verify error handling
### Deployment
- [ ] Deploy to staging
- [ ] Run integration tests
- [ ] Monitor for errors
- [ ] Deploy to production
- [ ] Monitor metrics
### Cleanup
- [ ] Remove compatibility layers (after validation period)
- [ ] Remove backup files
- [ ] Update documentation
- [ ] Archive migration scripts| Issue | Cause | Solution |
|---|---|---|
Evernote.Note is not a constructor | Old import style | Use Evernote.Types.Note |
callback is not a function | Mixed patterns | Use Promise or callback, not both |
Cannot read property 'then' | Using old callback-only method | Update to Promise-based method |
For CI/CD integration, see evernote-ci-integration.