Implement SimpleNote Web API - full REST API with Express

- Express server with CORS, JSON middleware
- Auth middleware (Bearer token)
- Document CRUD with markdown storage
- Library CRUD with nested support
- Tag indexing and search
- Error handler middleware
- Config from env vars
- Init script for data structure
This commit is contained in:
Erwin
2026-03-28 03:27:27 +00:00
parent 0e244d2b30
commit 825dfba2a7
22 changed files with 2864 additions and 20 deletions

90
scripts/init-data.js Normal file
View File

@@ -0,0 +1,90 @@
/**
* SimpleNote Web - Init Script
* Creates initial data structure and default library
*/
import { fileURLToPath } from 'url';
import { dirname, join, resolve } from 'path';
import { ensureDir, writeJSON, pathExists } from '../src/utils/fsHelper.js';
import { generateId } from '../src/utils/uuid.js';
import dotenv from 'dotenv';
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const projectRoot = resolve(__dirname, '..');
const dataRoot = resolve(projectRoot, process.env.DATA_ROOT || './data');
console.log(`[Init] Initializing data at: ${dataRoot}`);
const DATA_ROOT = dataRoot;
const LIBRARIES_DIR = join(DATA_ROOT, 'libraries');
const TOKENS_FILE = join(DATA_ROOT, '.auth-tokens.json');
const TAG_INDEX_FILE = join(DATA_ROOT, '.tag-index.json');
async function init() {
// Create directories
ensureDir(DATA_ROOT);
ensureDir(LIBRARIES_DIR);
// Init auth tokens
if (!pathExists(TOKENS_FILE)) {
const adminToken = process.env.ADMIN_TOKEN || 'snk_initial_admin_token_change_me';
writeJSON(TOKENS_FILE, {
version: 1,
tokens: [
{
token: adminToken,
label: 'initial-admin',
createdAt: new Date().toISOString(),
},
],
});
console.log(`[Init] Created .auth-tokens.json with admin token: ${adminToken}`);
} else {
console.log('[Init] .auth-tokens.json already exists');
}
// Init tag index
if (!pathExists(TAG_INDEX_FILE)) {
writeJSON(TAG_INDEX_FILE, {
version: 1,
updatedAt: new Date().toISOString(),
tags: {},
});
console.log('[Init] Created .tag-index.json');
} else {
console.log('[Init] .tag-index.json already exists');
}
// Create default library
const defaultLibPath = join(LIBRARIES_DIR, 'default');
const defaultLibMeta = join(defaultLibPath, '.library.json');
if (!pathExists(defaultLibMeta)) {
const libId = generateId();
const now = new Date().toISOString();
ensureDir(join(defaultLibPath, 'documents'));
ensureDir(join(defaultLibPath, 'sub-libraries'));
writeJSON(defaultLibMeta, {
id: libId,
name: 'Default Library',
parentId: null,
path: `libraries/${libId}`,
createdAt: now,
updatedAt: now,
});
console.log(`[Init] Created default library: ${libId}`);
} else {
console.log('[Init] Default library already exists');
}
console.log('[Init] Done!');
}
init().catch(err => {
console.error('[Init] Error:', err);
process.exit(1);
});