| name | evernote-local-dev-loop |
| description | Set up efficient local development workflow for Evernote integrations.
Use when configuring dev environment, setting up sandbox testing,
or optimizing development iteration speed.
Trigger with phrases like "evernote dev setup", "evernote local development",
"evernote sandbox", "test evernote locally".
|
| allowed-tools | Read, Write, Edit, Bash(npm:*), Bash(node:*), Grep |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Evernote Local Dev Loop
Overview
Configure an efficient local development environment for Evernote API integration with sandbox testing, hot reload, and debugging tools.
Prerequisites
Instructions
Step 1: Project Structure
mkdir evernote-project && cd evernote-project
npm init -y
npm install evernote dotenv nodemon express express-session
mkdir -p src/{routes,services,utils}
touch src/index.js src/evernote-client.js .env .env.example
evernote-project/
├── src/
│ ├── index.js # Express server entry
│ ├── evernote-client.js # Evernote client wrapper
│ ├── routes/
│ │ └── oauth.js # OAuth routes
│ ├── services/
│ │ └── notes.js # Note operations
│ └── utils/
│ └── enml.js # ENML helpers
├── .env # Local environment
├── .env.example # Template
└── package.json
Step 2: Environment Configuration
EVERNOTE_CONSUMER_KEY=your-consumer-key
EVERNOTE_CONSUMER_SECRET=your-consumer-secret
EVERNOTE_SANDBOX=true
EVERNOTE_DEV_TOKEN=your-sandbox-dev-token
SESSION_SECRET=dev-session-secret-change-in-prod
PORT=3000
NODE_ENV=development
EVERNOTE_CONSUMER_KEY=
EVERNOTE_CONSUMER_SECRET=
EVERNOTE_SANDBOX=true
EVERNOTE_DEV_TOKEN=
SESSION_SECRET=
PORT=3000
NODE_ENV=development
Step 3: Evernote Client Wrapper
const Evernote = require('evernote');
class EvernoteService {
constructor(accessToken) {
this.client = new Evernote.Client({
token: accessToken,
sandbox: process.env.EVERNOTE_SANDBOX === 'true'
});
this._noteStore = null;
this._userStore = null;
}
get noteStore() {
if (!this._noteStore) {
this._noteStore = this.client.getNoteStore();
}
return this._noteStore;
}
get userStore() {
if (!this._userStore) {
this._userStore = this.client.getUserStore();
}
.;
}
() {
.({
: process..,
: process..,
: process.. ===
});
}
() {
(!process..) {
();
}
(process..);
}
}
. = ;
Step 4: ENML Utility Helpers
const ENML_HEADER = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">`;
function wrapInENML(content) {
return `${ENML_HEADER}
<en-note>
${content}
</en-note>`;
}
function textToENML(text) {
const escaped = text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\n/g, '<br/>');
return wrapInENML(`<div>${escaped}</div>`);
}
function markdownToENML(markdown) {
let html = markdown
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
.(, )
.(, )
.(, )
.(, )
.(, )
.(, );
();
}
() {
;
}
() {
errors = [];
(!content.()) {
errors.();
}
(!content.()) {
errors.();
}
(!content.() || !content.()) {
errors.();
}
forbidden = [, , , , ];
forbidden.( {
(content.().(tag)) {
errors.();
}
});
{
: errors. === ,
errors
};
}
. = {
,
wrapInENML,
textToENML,
markdownToENML,
createTodo,
validateENML
};
Step 5: Express Server with OAuth
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const EvernoteService = require('./evernote-client');
const app = express();
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { secure: process.env.NODE_ENV === 'production' }
}));
app.use(express.json());
app.get('/auth/evernote', (req, res) => {
const client = EvernoteService.createOAuthClient();
const callbackUrl = `http://localhost:${process.env.PORT}/auth/evernote/callback`;
client.getRequestToken(callbackUrl, (error, oauthToken, oauthTokenSecret) => {
if (error) {
console.error(, error);
res.().({ : });
}
req.. = oauthToken;
req.. = oauthTokenSecret;
res.(client.(oauthToken));
});
});
app.(, {
client = .();
client.(
req..,
req..,
req..,
{
(error) {
.(, error);
res.().({ : });
}
req.. = accessToken;
req.. = results.;
res.({
: ,
: ,
: ((results.))
});
}
);
});
app.(, (req, res) => {
{
evernote = .();
user = evernote..();
notebooks = evernote..();
res.({
: user.,
: notebooks.,
: notebooks.( ({ : n., : n. }))
});
} (error) {
res.().({ : error. });
}
});
= process.. || ;
app.(, {
.();
.(, process.. === );
.();
.();
.();
});
Step 6: Package.json Scripts
{
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"test": "node --test",
"test:note": "node -e \"require('./src/test-note.js')\"",
"lint": "eslint src/"
}
}
Step 7: Quick Test Script
require('dotenv').config();
const EvernoteService = require('./evernote-client');
const { textToENML } = require('./utils/enml');
async function testCreateNote() {
const evernote = EvernoteService.createDevClient();
const note = new (require('evernote')).Types.Note();
note.title = `Dev Test - ${new Date().toISOString()}`;
note.content = textToENML('This is a test note from the dev loop');
const created = await evernote.noteStore.createNote(note);
console.log('Created note:', created.guid);
await evernote.noteStore.deleteNote(created.guid);
console.log('Deleted test note');
console.();
}
().(.);
Development Workflow
npm run dev
curl http://localhost:3000/dev/test
npm run test:note
Sandbox vs Production
| Aspect | Sandbox | Production |
|---|
| URL | sandbox.evernote.com | www.evernote.com |
| Dev Token | Available | Not available |
| Rate Limits | Same | Same |
| Data | Separate account | Real user data |
| OAuth | Required for apps | Required |
Output
- Working local development server
- Hot-reload enabled with nodemon
- OAuth flow implemented
- Dev token shortcut for quick testing
- ENML utility functions
Error Handling
| Error | Cause | Solution |
|---|
EVERNOTE_DEV_TOKEN not set | Missing dev token | Get from sandbox.evernote.com/api/DeveloperToken.action |
Invalid consumer key | Wrong sandbox vs prod | Verify EVERNOTE_SANDBOX matches your key type |
Session undefined | Missing express-session | Ensure session middleware is configured |
Resources
Next Steps
Proceed to evernote-sdk-patterns for advanced SDK usage patterns.