markdown-notes-engine 1.0.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +554 -119
- package/lib/backend/db/connection.js +127 -0
- package/lib/backend/db/schema.sql +144 -0
- package/lib/backend/github.js +2 -4
- package/lib/backend/index.js +69 -28
- package/lib/backend/markdown.js +4 -6
- package/lib/backend/routes/notes.js +35 -4
- package/lib/backend/routes/search.js +2 -2
- package/lib/backend/routes/upload.js +33 -6
- package/lib/backend/storage.js +2 -4
- package/lib/backend/version-control.js +458 -0
- package/lib/frontend/index.js +3 -6
- package/lib/index.js +5 -16
- package/package.json +20 -30
- package/lib/backend/github.mjs +0 -316
- package/lib/backend/index.mjs +0 -74
- package/lib/backend/markdown.mjs +0 -60
- package/lib/backend/routes/notes.mjs +0 -197
- package/lib/backend/routes/search.mjs +0 -28
- package/lib/backend/routes/upload.mjs +0 -122
- package/lib/backend/storage.mjs +0 -119
- package/lib/frontend/index.mjs +0 -15
- package/lib/index.mjs +0 -17
package/README.md
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
# Markdown Notes Engine
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/markdown-notes-engine)
|
|
3
|
+
[](https://www.npmjs.com/package/@camthomp1/markdown-notes-engine)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
A complete, production-ready markdown note-taking engine with GitHub integration and media hosting. Add powerful note-taking capabilities to any Node.js application with just a few lines of code.
|
|
6
|
+
A complete, production-ready markdown note-taking engine with Git-like version control (PostgreSQL) or GitHub integration and media hosting (Cloudflare R2/AWS S3). Add powerful note-taking capabilities to any Node.js application with just a few lines of code.
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
10
|
- **Full Markdown Support** - Rich markdown editing with live preview
|
|
11
|
-
- **
|
|
11
|
+
- **Git-Like Version Control** - Choose between PostgreSQL (recommended) or GitHub for version control
|
|
12
|
+
- **PostgreSQL**: Content-addressable storage with SHA-256 hashing, commit history, and branching
|
|
13
|
+
- **GitHub**: Traditional GitHub-based storage (legacy support)
|
|
14
|
+
- **Content-Addressable Storage** - Deduplication and integrity verification
|
|
15
|
+
- **Full Commit History** - Track every change with parent references and timestamps
|
|
12
16
|
- **Media Hosting** - Image and video uploads to Cloudflare R2 or AWS S3
|
|
17
|
+
- **Full-Text Search** - PostgreSQL tsvector search or GitHub code search
|
|
13
18
|
- **Syntax Highlighting** - Beautiful code blocks with highlight.js
|
|
14
19
|
- **Auto-save** - Never lose your work with automatic saving
|
|
15
|
-
- **
|
|
16
|
-
- **Dark Mode** - Built-in dark mode support
|
|
20
|
+
- **Dark Mode** - Built-in dark mode support with persistence
|
|
17
21
|
- **Responsive** - Works beautifully on mobile and desktop
|
|
18
22
|
- **Keyboard Shortcuts** - Boost productivity with keyboard shortcuts
|
|
19
23
|
- **Drag & Drop** - Upload media with drag and drop
|
|
24
|
+
- **File History** - Get complete commit history for any file
|
|
20
25
|
|
|
21
26
|
## Quick Start
|
|
22
27
|
|
|
@@ -26,65 +31,108 @@ A complete, production-ready markdown note-taking engine with GitHub integration
|
|
|
26
31
|
npm install markdown-notes-engine
|
|
27
32
|
```
|
|
28
33
|
|
|
29
|
-
###
|
|
34
|
+
### Basic Usage
|
|
30
35
|
|
|
31
|
-
This package
|
|
36
|
+
This package is ESM-only. Use ES module `import` statements:
|
|
32
37
|
|
|
33
|
-
**ES Modules (import)**
|
|
34
38
|
```javascript
|
|
35
|
-
import
|
|
36
|
-
|
|
39
|
+
import express from 'express';
|
|
40
|
+
import { createNotesRouter } from 'markdown-notes-engine';
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
const app = express();
|
|
43
|
+
|
|
44
|
+
async function startServer() {
|
|
45
|
+
const notesRouter = await createNotesRouter({
|
|
46
|
+
database: {
|
|
47
|
+
host: 'localhost',
|
|
48
|
+
port: 5432,
|
|
49
|
+
database: 'markdown_notes',
|
|
50
|
+
user: 'postgres',
|
|
51
|
+
password: 'your_password',
|
|
52
|
+
branch: 'main',
|
|
53
|
+
author: 'your_name'
|
|
54
|
+
},
|
|
55
|
+
storage: {
|
|
56
|
+
type: 'r2',
|
|
57
|
+
accountId: process.env.R2_ACCOUNT_ID,
|
|
58
|
+
accessKeyId: process.env.R2_ACCESS_KEY_ID,
|
|
59
|
+
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
|
|
60
|
+
bucketName: process.env.R2_BUCKET_NAME,
|
|
61
|
+
publicUrl: process.env.R2_PUBLIC_URL
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
app.use('/api/notes', notesRouter);
|
|
66
|
+
app.listen(3000, () => {
|
|
67
|
+
console.log('Notes engine running on http://localhost:3000');
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
startServer();
|
|
41
72
|
```
|
|
42
73
|
|
|
43
|
-
|
|
74
|
+
## Version Control Options
|
|
75
|
+
|
|
76
|
+
### Option 1: PostgreSQL (Recommended)
|
|
44
77
|
|
|
45
|
-
|
|
46
|
-
<summary><b>ES Modules (import)</b></summary>
|
|
78
|
+
PostgreSQL-backed version control with Git-like architecture:
|
|
47
79
|
|
|
48
80
|
```javascript
|
|
49
|
-
import express from 'express';
|
|
50
81
|
import { createNotesRouter } from 'markdown-notes-engine';
|
|
51
82
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
83
|
+
const notesRouter = await createNotesRouter({
|
|
84
|
+
database: {
|
|
85
|
+
// Option A: Connection string (Supabase, Heroku, etc.)
|
|
86
|
+
connectionString: process.env.DATABASE_URL,
|
|
87
|
+
branch: 'main',
|
|
88
|
+
author: 'your_name'
|
|
89
|
+
|
|
90
|
+
// Option B: Individual parameters (local PostgreSQL)
|
|
91
|
+
// host: 'localhost',
|
|
92
|
+
// port: 5432,
|
|
93
|
+
// database: 'markdown_notes',
|
|
94
|
+
// user: 'postgres',
|
|
95
|
+
// password: 'your_password',
|
|
96
|
+
// branch: 'main',
|
|
97
|
+
// author: 'your_name'
|
|
59
98
|
},
|
|
60
99
|
storage: {
|
|
61
|
-
type: 'r2',
|
|
100
|
+
type: 'r2', // or 's3'
|
|
62
101
|
accountId: process.env.R2_ACCOUNT_ID,
|
|
63
102
|
accessKeyId: process.env.R2_ACCESS_KEY_ID,
|
|
64
103
|
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
|
|
65
104
|
bucketName: process.env.R2_BUCKET_NAME,
|
|
66
105
|
publicUrl: process.env.R2_PUBLIC_URL
|
|
106
|
+
},
|
|
107
|
+
options: {
|
|
108
|
+
autoInitSchema: true, // Auto-initialize database schema
|
|
109
|
+
autoUpdateReadme: true // Auto-update README.md with note list
|
|
67
110
|
}
|
|
68
111
|
});
|
|
69
|
-
|
|
70
|
-
app.use('/api', notesRouter);
|
|
71
112
|
```
|
|
72
|
-
</details>
|
|
73
113
|
|
|
74
|
-
|
|
75
|
-
|
|
114
|
+
**PostgreSQL Features:**
|
|
115
|
+
- Content-addressable storage (SHA-256 hashing)
|
|
116
|
+
- Full commit history with parent references
|
|
117
|
+
- Branches support
|
|
118
|
+
- No size limits
|
|
119
|
+
- Full-text search with PostgreSQL tsvector
|
|
120
|
+
- Automatic schema migrations
|
|
121
|
+
- Works with local PostgreSQL, Supabase, Heroku Postgres, etc.
|
|
76
122
|
|
|
77
|
-
|
|
78
|
-
const express = require('express');
|
|
79
|
-
const { createNotesRouter } = require('markdown-notes-engine');
|
|
123
|
+
### Option 2: GitHub (Legacy)
|
|
80
124
|
|
|
81
|
-
|
|
125
|
+
GitHub-based version control:
|
|
82
126
|
|
|
83
|
-
|
|
127
|
+
```javascript
|
|
128
|
+
import { createNotesRouter } from 'markdown-notes-engine';
|
|
129
|
+
|
|
130
|
+
const notesRouter = await createNotesRouter({
|
|
84
131
|
github: {
|
|
85
132
|
token: process.env.GITHUB_TOKEN,
|
|
86
133
|
owner: process.env.GITHUB_OWNER,
|
|
87
|
-
repo: process.env.GITHUB_REPO
|
|
134
|
+
repo: process.env.GITHUB_REPO,
|
|
135
|
+
branch: 'main'
|
|
88
136
|
},
|
|
89
137
|
storage: {
|
|
90
138
|
type: 'r2',
|
|
@@ -95,145 +143,518 @@ const notesRouter = createNotesRouter({
|
|
|
95
143
|
publicUrl: process.env.R2_PUBLIC_URL
|
|
96
144
|
}
|
|
97
145
|
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Note:** GitHub mode requires the optional `@octokit/rest` dependency:
|
|
149
|
+
```bash
|
|
150
|
+
npm install @octokit/rest
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Remote Database Support
|
|
98
154
|
|
|
99
|
-
|
|
155
|
+
Works with any PostgreSQL database:
|
|
156
|
+
|
|
157
|
+
### Supabase
|
|
158
|
+
```javascript
|
|
159
|
+
{
|
|
160
|
+
database: {
|
|
161
|
+
connectionString: process.env.DATABASE_URL, // Use Connection Pooling URL (port 6543)
|
|
162
|
+
branch: 'main',
|
|
163
|
+
author: 'your_name'
|
|
164
|
+
}
|
|
165
|
+
}
|
|
100
166
|
```
|
|
101
|
-
</details>
|
|
102
167
|
|
|
103
|
-
|
|
168
|
+
See [docs/SUPABASE.md](docs/SUPABASE.md) for detailed Supabase setup instructions.
|
|
169
|
+
|
|
170
|
+
### Heroku Postgres
|
|
171
|
+
```javascript
|
|
172
|
+
{
|
|
173
|
+
database: {
|
|
174
|
+
connectionString: process.env.DATABASE_URL,
|
|
175
|
+
ssl: 'require',
|
|
176
|
+
branch: 'main',
|
|
177
|
+
author: 'your_name'
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Local PostgreSQL
|
|
183
|
+
```javascript
|
|
184
|
+
{
|
|
185
|
+
database: {
|
|
186
|
+
host: 'localhost',
|
|
187
|
+
port: 5432,
|
|
188
|
+
database: 'markdown_notes',
|
|
189
|
+
user: 'postgres',
|
|
190
|
+
password: 'your_password',
|
|
191
|
+
branch: 'main',
|
|
192
|
+
author: 'your_name'
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Frontend Integration
|
|
198
|
+
|
|
199
|
+
### Using the Bundled Editor
|
|
104
200
|
|
|
105
201
|
```html
|
|
106
|
-
|
|
202
|
+
<!DOCTYPE html>
|
|
203
|
+
<html>
|
|
204
|
+
<head>
|
|
205
|
+
<title>My Notes App</title>
|
|
206
|
+
<link rel="stylesheet" href="node_modules/markdown-notes-engine/lib/frontend/styles.css">
|
|
207
|
+
</head>
|
|
208
|
+
<body>
|
|
209
|
+
<div id="notes-app"></div>
|
|
210
|
+
|
|
211
|
+
<script type="module">
|
|
212
|
+
import { NotesEditor } from 'markdown-notes-engine/frontend';
|
|
213
|
+
|
|
214
|
+
const editor = new NotesEditor({
|
|
215
|
+
container: '#notes-app',
|
|
216
|
+
apiEndpoint: '/api/notes',
|
|
217
|
+
theme: 'dark',
|
|
218
|
+
autoSave: true,
|
|
219
|
+
autoSaveDelay: 2000
|
|
220
|
+
});
|
|
221
|
+
</script>
|
|
222
|
+
</body>
|
|
223
|
+
</html>
|
|
224
|
+
```
|
|
107
225
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
226
|
+
### Custom Frontend
|
|
227
|
+
|
|
228
|
+
Build your own frontend using the API endpoints:
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// Get file structure
|
|
232
|
+
const structure = await fetch('/api/notes/structure').then(r => r.json());
|
|
233
|
+
|
|
234
|
+
// Get note content
|
|
235
|
+
const note = await fetch('/api/notes/note?path=my-note.md').then(r => r.json());
|
|
236
|
+
|
|
237
|
+
// Save note
|
|
238
|
+
await fetch('/api/notes/note', {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
headers: { 'Content-Type': 'application/json' },
|
|
241
|
+
body: JSON.stringify({ path: 'my-note.md', content: '# Hello World' })
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Delete note (supports both query params and body)
|
|
245
|
+
await fetch('/api/notes/note?path=my-note.md', { method: 'DELETE' });
|
|
246
|
+
// or
|
|
247
|
+
await fetch('/api/notes/note', {
|
|
248
|
+
method: 'DELETE',
|
|
249
|
+
headers: { 'Content-Type': 'application/json' },
|
|
250
|
+
body: JSON.stringify({ path: 'my-note.md' })
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Get file history (PostgreSQL only)
|
|
254
|
+
const history = await fetch('/api/notes/history?path=my-note.md').then(r => r.json());
|
|
255
|
+
|
|
256
|
+
// Search notes
|
|
257
|
+
const results = await fetch('/api/notes/search?q=hello').then(r => r.json());
|
|
115
258
|
```
|
|
116
259
|
|
|
117
|
-
##
|
|
260
|
+
## API Reference
|
|
261
|
+
|
|
262
|
+
### Complete API Endpoints
|
|
263
|
+
|
|
264
|
+
| Method | Endpoint | Description | Params |
|
|
265
|
+
|--------|----------|-------------|--------|
|
|
266
|
+
| GET | `/structure` | Get file tree | - |
|
|
267
|
+
| GET | `/note` | Get note content | `?path=file.md` |
|
|
268
|
+
| POST | `/note` | Save/update note | `{ path, content }` |
|
|
269
|
+
| DELETE | `/note` | Delete note | `?path=file.md` or `{ path }` |
|
|
270
|
+
| POST | `/folder` | Create folder | `{ path }` |
|
|
271
|
+
| DELETE | `/folder` | Delete folder | `{ path }` |
|
|
272
|
+
| GET | `/history` | Get file commit history | `?path=file.md` (PostgreSQL only) |
|
|
273
|
+
| GET | `/search` | Full-text search | `?q=query` |
|
|
274
|
+
| POST | `/upload-image` | Upload image | FormData with `image` file |
|
|
275
|
+
| POST | `/upload-video` | Upload video | FormData with `video` file |
|
|
276
|
+
| POST | `/upload-image-base64` | Upload base64 image | `{ image, filename, folder }` |
|
|
277
|
+
| POST | `/render` | Render markdown | `{ markdown }` |
|
|
278
|
+
|
|
279
|
+
### Response Formats
|
|
280
|
+
|
|
281
|
+
**Structure Response:**
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"structure": [
|
|
285
|
+
{
|
|
286
|
+
"name": "folder",
|
|
287
|
+
"type": "folder",
|
|
288
|
+
"path": "folder",
|
|
289
|
+
"children": [
|
|
290
|
+
{
|
|
291
|
+
"name": "note.md",
|
|
292
|
+
"type": "file",
|
|
293
|
+
"path": "folder/note.md"
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
]
|
|
298
|
+
}
|
|
299
|
+
```
|
|
118
300
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
301
|
+
**Note Response:**
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"path": "my-note.md",
|
|
305
|
+
"content": "# Hello World\n\nThis is my note.",
|
|
306
|
+
"sha": "abc123..."
|
|
307
|
+
}
|
|
308
|
+
```
|
|
122
309
|
|
|
123
|
-
|
|
310
|
+
**Save Response:**
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"success": true,
|
|
314
|
+
"path": "my-note.md",
|
|
315
|
+
"sha": "def456...",
|
|
316
|
+
"commit": {
|
|
317
|
+
"sha": "commit-sha",
|
|
318
|
+
"message": "Update my-note.md"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
124
322
|
|
|
125
|
-
|
|
323
|
+
**History Response (PostgreSQL):**
|
|
324
|
+
```json
|
|
325
|
+
[
|
|
326
|
+
{
|
|
327
|
+
"sha": "commit-id",
|
|
328
|
+
"message": "Update note",
|
|
329
|
+
"author": "user",
|
|
330
|
+
"date": "2025-01-03T12:00:00.000Z",
|
|
331
|
+
"blobHash": "content-hash",
|
|
332
|
+
"changed": true
|
|
333
|
+
}
|
|
334
|
+
]
|
|
335
|
+
```
|
|
126
336
|
|
|
127
|
-
|
|
128
|
-
|
|
337
|
+
**Search Response:**
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"results": [
|
|
341
|
+
{
|
|
342
|
+
"path": "my-note.md",
|
|
343
|
+
"content": "# Hello World",
|
|
344
|
+
"score": 0.95,
|
|
345
|
+
"preview": "...matching text..."
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
}
|
|
349
|
+
```
|
|
129
350
|
|
|
130
|
-
|
|
351
|
+
**Upload Response:**
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"success": true,
|
|
355
|
+
"url": "https://your-bucket.r2.dev/images/abc123.jpg",
|
|
356
|
+
"path": "images/abc123.jpg",
|
|
357
|
+
"filename": "abc123.jpg"
|
|
358
|
+
}
|
|
359
|
+
```
|
|
131
360
|
|
|
132
|
-
|
|
361
|
+
## Configuration Options
|
|
133
362
|
|
|
134
|
-
###
|
|
135
|
-
- **`createNotesRouter(config)`** - Express router with all API endpoints
|
|
136
|
-
- **`GitHubClient`** - GitHub API wrapper for note storage
|
|
137
|
-
- **`StorageClient`** - R2/S3 client for media uploads
|
|
138
|
-
- **`MarkdownRenderer`** - Markdown to HTML renderer with syntax highlighting
|
|
363
|
+
### Database Configuration
|
|
139
364
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
365
|
+
```javascript
|
|
366
|
+
{
|
|
367
|
+
database: {
|
|
368
|
+
// Connection string (recommended for remote databases)
|
|
369
|
+
connectionString: 'postgresql://user:pass@host:5432/db',
|
|
370
|
+
|
|
371
|
+
// Or individual parameters
|
|
372
|
+
host: 'localhost',
|
|
373
|
+
port: 5432,
|
|
374
|
+
database: 'markdown_notes',
|
|
375
|
+
user: 'postgres',
|
|
376
|
+
password: 'your_password',
|
|
377
|
+
|
|
378
|
+
// Connection pool settings
|
|
379
|
+
maxConnections: 20,
|
|
380
|
+
idleTimeout: 30,
|
|
381
|
+
connectionTimeout: 10,
|
|
382
|
+
|
|
383
|
+
// SSL configuration
|
|
384
|
+
ssl: 'prefer', // 'require', 'prefer', or false
|
|
385
|
+
|
|
386
|
+
// Version control settings
|
|
387
|
+
branch: 'main',
|
|
388
|
+
author: 'your_name'
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
```
|
|
143
392
|
|
|
144
|
-
|
|
393
|
+
### Storage Configuration
|
|
145
394
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
395
|
+
**Cloudflare R2:**
|
|
396
|
+
```javascript
|
|
397
|
+
{
|
|
398
|
+
storage: {
|
|
399
|
+
type: 'r2',
|
|
400
|
+
accountId: 'your-account-id',
|
|
401
|
+
accessKeyId: 'your-access-key-id',
|
|
402
|
+
secretAccessKey: 'your-secret-key',
|
|
403
|
+
bucketName: 'your-bucket',
|
|
404
|
+
publicUrl: 'https://pub-xxxxx.r2.dev'
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
```
|
|
149
408
|
|
|
150
|
-
|
|
409
|
+
**AWS S3:**
|
|
410
|
+
```javascript
|
|
411
|
+
{
|
|
412
|
+
storage: {
|
|
413
|
+
type: 's3',
|
|
414
|
+
region: 'us-east-1',
|
|
415
|
+
accessKeyId: 'your-access-key-id',
|
|
416
|
+
secretAccessKey: 'your-secret-key',
|
|
417
|
+
bucketName: 'your-bucket',
|
|
418
|
+
publicUrl: 'https://your-bucket.s3.amazonaws.com'
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
151
422
|
|
|
152
|
-
|
|
153
|
-
GITHUB_TOKEN=ghp_xxxxxxxxxxxx
|
|
154
|
-
GITHUB_OWNER=your-username
|
|
155
|
-
GITHUB_REPO=your-notes-repo
|
|
423
|
+
### Options
|
|
156
424
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
425
|
+
```javascript
|
|
426
|
+
{
|
|
427
|
+
options: {
|
|
428
|
+
autoInitSchema: true, // Automatically initialize database schema
|
|
429
|
+
autoUpdateReadme: true // Auto-update README.md with note list
|
|
430
|
+
}
|
|
431
|
+
}
|
|
162
432
|
```
|
|
163
433
|
|
|
164
|
-
##
|
|
434
|
+
## Database Schema
|
|
435
|
+
|
|
436
|
+
The PostgreSQL version control uses a Git-like architecture:
|
|
165
437
|
|
|
166
|
-
|
|
438
|
+
- **blobs**: Content storage (content-addressable by SHA-256)
|
|
439
|
+
- **commits**: Commit records with messages, authors, and timestamps
|
|
440
|
+
- **trees**: File path to blob hash mappings for each commit
|
|
441
|
+
- **branches**: Named pointers to commits (like Git branches)
|
|
442
|
+
- **media**: Uploaded media file references
|
|
443
|
+
- **search_index**: Full-text search index using PostgreSQL tsvector
|
|
444
|
+
|
|
445
|
+
See [lib/backend/db/schema.sql](lib/backend/db/schema.sql) for the complete schema.
|
|
446
|
+
|
|
447
|
+
## Migration Guide
|
|
448
|
+
|
|
449
|
+
If you have an existing database from an older version, the schema includes automatic migrations. Simply restart your application with `autoInitSchema: true` and the migrations will run automatically.
|
|
450
|
+
|
|
451
|
+
See [MIGRATION.md](MIGRATION.md) for detailed migration instructions.
|
|
452
|
+
|
|
453
|
+
## Examples
|
|
454
|
+
|
|
455
|
+
Check out the `/examples` directory for complete working examples:
|
|
456
|
+
|
|
457
|
+
- **[postgres-example.js](examples/postgres-example.js)** - PostgreSQL version control with full Git-like history
|
|
458
|
+
- **[Express App](examples/express-app/)** - GitHub-based version control (legacy)
|
|
459
|
+
- **[.env.example](examples/.env.example)** - Environment variable template
|
|
460
|
+
|
|
461
|
+
## Version Control Comparison
|
|
462
|
+
|
|
463
|
+
| Feature | PostgreSQL | GitHub |
|
|
464
|
+
|---------|-----------|--------|
|
|
465
|
+
| Storage Limits | Unlimited | 100GB per repo |
|
|
466
|
+
| API Dependencies | None | GitHub API required |
|
|
467
|
+
| Speed | Fast (local or pooled DB) | Network dependent |
|
|
468
|
+
| Search | PostgreSQL full-text | GitHub code search |
|
|
469
|
+
| Control | Full ownership | External service |
|
|
470
|
+
| Cost | Database hosting | Free for public repos |
|
|
471
|
+
| Version History | Full Git-like history | Native Git history |
|
|
472
|
+
| File History | ✅ Built-in | ❌ Not available |
|
|
473
|
+
| Branching | ✅ Supported | ✅ Supported |
|
|
474
|
+
| Content Deduplication | ✅ SHA-256 hashing | ❌ No |
|
|
475
|
+
|
|
476
|
+
## Architecture
|
|
477
|
+
|
|
478
|
+
### Backend Modules
|
|
479
|
+
|
|
480
|
+
- **`createNotesRouter(config)`** - Express router factory (async function)
|
|
481
|
+
- **`VersionControlClient`** - PostgreSQL-backed Git-like version control
|
|
482
|
+
- **`DatabaseConnection`** - PostgreSQL connection pool manager (uses `postgres` package)
|
|
483
|
+
- **`GitHubClient`** - GitHub API wrapper for note storage (legacy, requires `@octokit/rest`)
|
|
484
|
+
- **`StorageClient`** - R2/S3 client for media uploads (uses AWS SDK)
|
|
485
|
+
- **`MarkdownRenderer`** - Markdown to HTML renderer with syntax highlighting
|
|
486
|
+
|
|
487
|
+
### Frontend Component
|
|
488
|
+
|
|
489
|
+
- **`NotesEditor`** - Complete note-taking UI component with:
|
|
490
|
+
- Markdown editor with live preview
|
|
491
|
+
- File tree navigation
|
|
492
|
+
- Dark mode support
|
|
493
|
+
- Keyboard shortcuts
|
|
494
|
+
- Drag & drop media uploads
|
|
495
|
+
- Auto-save functionality
|
|
167
496
|
|
|
168
497
|
### Project Structure
|
|
169
498
|
|
|
170
499
|
```
|
|
171
500
|
markdown-notes-engine/
|
|
172
|
-
├── lib/
|
|
173
|
-
│ ├── backend/
|
|
174
|
-
│ │ ├──
|
|
175
|
-
│ │
|
|
176
|
-
│
|
|
177
|
-
│ ├──
|
|
178
|
-
│
|
|
179
|
-
├──
|
|
180
|
-
│ └──
|
|
181
|
-
├──
|
|
182
|
-
├──
|
|
183
|
-
|
|
501
|
+
├── lib/ # NPM package source (ESM)
|
|
502
|
+
│ ├── backend/ # Express router and API
|
|
503
|
+
│ │ ├── db/ # Database schema and connection
|
|
504
|
+
│ │ │ ├── connection.js # PostgreSQL connection manager
|
|
505
|
+
│ │ │ └── schema.sql # Database schema with migrations
|
|
506
|
+
│ │ ├── routes/ # API route handlers
|
|
507
|
+
│ │ │ ├── notes.js # Note CRUD operations
|
|
508
|
+
│ │ │ ├── search.js # Search functionality
|
|
509
|
+
│ │ │ └── upload.js # Media upload handlers
|
|
510
|
+
│ │ ├── index.js # Main backend entry point
|
|
511
|
+
│ │ ├── github.js # GitHub client (legacy)
|
|
512
|
+
│ │ ├── version-control.js # PostgreSQL version control
|
|
513
|
+
│ │ ├── storage.js # S3/R2 storage client
|
|
514
|
+
│ │ └── markdown.js # Markdown renderer
|
|
515
|
+
│ ├── frontend/ # Editor UI component
|
|
516
|
+
│ │ ├── index.js # NotesEditor class
|
|
517
|
+
│ │ └── styles.css # Styles and dark mode
|
|
518
|
+
│ └── index.js # Main package entry point
|
|
519
|
+
├── examples/ # Usage examples
|
|
520
|
+
│ ├── postgres-example.js # PostgreSQL example
|
|
521
|
+
│ ├── .env.example # Environment template
|
|
522
|
+
│ └── express-app/ # GitHub integration example
|
|
523
|
+
├── docs/ # Documentation
|
|
524
|
+
│ └── SUPABASE.md # Supabase setup guide
|
|
525
|
+
├── MIGRATION.md # Database migration guide
|
|
526
|
+
└── package.json # Package configuration (ESM)
|
|
184
527
|
```
|
|
185
528
|
|
|
529
|
+
## Requirements
|
|
530
|
+
|
|
531
|
+
- **Node.js** >= 16.0.0
|
|
532
|
+
- **For PostgreSQL version control** (recommended):
|
|
533
|
+
- PostgreSQL database (version 12 or higher)
|
|
534
|
+
- Works with local PostgreSQL, Supabase, Heroku Postgres, etc.
|
|
535
|
+
- **For GitHub version control** (legacy):
|
|
536
|
+
- GitHub personal access token with `repo` scope
|
|
537
|
+
- Install optional dependency: `npm install @octokit/rest`
|
|
538
|
+
- **For media hosting**:
|
|
539
|
+
- Cloudflare R2 or AWS S3 account
|
|
540
|
+
|
|
541
|
+
## Keyboard Shortcuts
|
|
542
|
+
|
|
543
|
+
- `Ctrl/Cmd + S` - Save note
|
|
544
|
+
- `Ctrl/Cmd + P` - Toggle preview mode
|
|
545
|
+
- `Ctrl/Cmd + N` - New note
|
|
546
|
+
- `Ctrl/Cmd + U` - Upload image
|
|
547
|
+
- `Ctrl/Cmd + Shift + U` - Upload video
|
|
548
|
+
|
|
549
|
+
## Development
|
|
550
|
+
|
|
186
551
|
### Running the Demo
|
|
187
552
|
|
|
188
553
|
```bash
|
|
189
554
|
# Install dependencies
|
|
190
555
|
npm install
|
|
191
556
|
|
|
192
|
-
#
|
|
193
|
-
cp
|
|
557
|
+
# Copy environment template
|
|
558
|
+
cp examples/.env.example .env
|
|
559
|
+
|
|
560
|
+
# Edit .env with your credentials
|
|
561
|
+
# Set up PostgreSQL database or GitHub token
|
|
562
|
+
# Configure R2/S3 storage
|
|
194
563
|
|
|
195
|
-
# Start the server
|
|
564
|
+
# Start the development server
|
|
196
565
|
npm run dev
|
|
197
566
|
```
|
|
198
567
|
|
|
199
|
-
Open `http://localhost:
|
|
568
|
+
Open `http://localhost:3000` to see the demo application.
|
|
200
569
|
|
|
201
|
-
|
|
570
|
+
### Building the Package
|
|
202
571
|
|
|
203
|
-
|
|
572
|
+
The package is already built and ready to use. All source files are in the `lib/` directory and use ES modules.
|
|
204
573
|
|
|
205
|
-
|
|
206
|
-
- `GET /note` - Get note content
|
|
207
|
-
- `POST /note` - Save note
|
|
208
|
-
- `DELETE /note` - Delete note
|
|
209
|
-
- `POST /folder` - Create folder
|
|
210
|
-
- `DELETE /folder` - Delete folder
|
|
211
|
-
- `POST /upload-image` - Upload image
|
|
212
|
-
- `POST /upload-video` - Upload video
|
|
213
|
-
- `POST /render` - Render markdown
|
|
214
|
-
- `GET /search` - Search notes
|
|
574
|
+
## Environment Variables
|
|
215
575
|
|
|
216
|
-
|
|
576
|
+
### PostgreSQL Setup
|
|
217
577
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
578
|
+
```env
|
|
579
|
+
# Database Configuration
|
|
580
|
+
DB_HOST=localhost
|
|
581
|
+
DB_PORT=5432
|
|
582
|
+
DB_NAME=markdown_notes
|
|
583
|
+
DB_USER=postgres
|
|
584
|
+
DB_PASSWORD=your_password_here
|
|
585
|
+
|
|
586
|
+
# Or use connection string (Supabase, Heroku, etc.)
|
|
587
|
+
# DATABASE_URL=postgresql://postgres:password@host:6543/postgres
|
|
588
|
+
|
|
589
|
+
# Storage Configuration (R2 or S3)
|
|
590
|
+
R2_ACCOUNT_ID=your_account_id
|
|
591
|
+
R2_ACCESS_KEY_ID=your_access_key_id
|
|
592
|
+
R2_SECRET_ACCESS_KEY=your_secret_access_key
|
|
593
|
+
R2_BUCKET_NAME=your_bucket_name
|
|
594
|
+
R2_PUBLIC_URL=https://pub-xxxxxx.r2.dev
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
### GitHub Setup (Legacy)
|
|
598
|
+
|
|
599
|
+
```env
|
|
600
|
+
# GitHub Configuration
|
|
601
|
+
GITHUB_TOKEN=ghp_xxxxxxxxxxxx
|
|
602
|
+
GITHUB_OWNER=your-username
|
|
603
|
+
GITHUB_REPO=your-notes-repo
|
|
604
|
+
GITHUB_BRANCH=main
|
|
605
|
+
|
|
606
|
+
# Storage Configuration
|
|
607
|
+
R2_ACCOUNT_ID=your_account_id
|
|
608
|
+
R2_ACCESS_KEY_ID=your_access_key_id
|
|
609
|
+
R2_SECRET_ACCESS_KEY=your_secret_access_key
|
|
610
|
+
R2_BUCKET_NAME=your_bucket_name
|
|
611
|
+
R2_PUBLIC_URL=https://pub-xxxxxx.r2.dev
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## Troubleshooting
|
|
615
|
+
|
|
616
|
+
### Database Connection Issues
|
|
617
|
+
|
|
618
|
+
**Error: "connect ETIMEDOUT"**
|
|
619
|
+
- For Supabase: Use Connection Pooling URL (port 6543), not Direct Connection
|
|
620
|
+
- Increase `connectionTimeout` in database config
|
|
621
|
+
- Check firewall settings
|
|
622
|
+
|
|
623
|
+
**Error: "column does not exist"**
|
|
624
|
+
- The schema has automatic migrations
|
|
625
|
+
- Restart your app with `autoInitSchema: true`
|
|
626
|
+
- See [MIGRATION.md](MIGRATION.md) for manual migration steps
|
|
627
|
+
|
|
628
|
+
**Error: "UNSAFE_TRANSACTION"**
|
|
629
|
+
- This is handled automatically by the `postgres` package
|
|
630
|
+
- Ensure you're using the latest version
|
|
631
|
+
|
|
632
|
+
### Import/Module Issues
|
|
633
|
+
|
|
634
|
+
**Error: "Cannot use import statement outside a module"**
|
|
635
|
+
- Add `"type": "module"` to your package.json
|
|
636
|
+
- This package is ESM-only
|
|
223
637
|
|
|
224
638
|
## Contributing
|
|
225
639
|
|
|
226
640
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
227
641
|
|
|
642
|
+
1. Fork the repository
|
|
643
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
644
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
645
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
646
|
+
5. Open a Pull Request
|
|
647
|
+
|
|
228
648
|
## License
|
|
229
649
|
|
|
230
650
|
MIT License - see [LICENSE](LICENSE) for details
|
|
231
651
|
|
|
232
652
|
## Support
|
|
233
653
|
|
|
234
|
-
- 📖 [Documentation](lib/README.md)
|
|
235
|
-
- 💬 [Issues](https://github.com/cdthomp1/notes/issues)
|
|
236
|
-
- 📧 [
|
|
654
|
+
- 📖 [Full Documentation](lib/README.md)
|
|
655
|
+
- 💬 [GitHub Issues](https://github.com/cdthomp1/markdown-notes-engine/issues)
|
|
656
|
+
- 📧 [Supabase Setup Guide](docs/SUPABASE.md)
|
|
657
|
+
- 🔄 [Migration Guide](MIGRATION.md)
|
|
237
658
|
|
|
238
659
|
## Acknowledgments
|
|
239
660
|
|
|
@@ -241,9 +662,23 @@ Built with:
|
|
|
241
662
|
- [Express](https://expressjs.com/) - Web framework
|
|
242
663
|
- [Marked](https://marked.js.org/) - Markdown parser
|
|
243
664
|
- [Highlight.js](https://highlightjs.org/) - Syntax highlighting
|
|
244
|
-
- [
|
|
665
|
+
- [PostgreSQL](https://www.postgresql.org/) - Database and version control
|
|
666
|
+
- [postgres](https://github.com/porsager/postgres) - PostgreSQL client for Node.js
|
|
667
|
+
- [Octokit](https://github.com/octokit/rest.js/) - GitHub API client (optional)
|
|
245
668
|
- [AWS SDK](https://aws.amazon.com/sdk-for-javascript/) - S3/R2 client
|
|
246
669
|
|
|
670
|
+
## Changelog
|
|
671
|
+
|
|
672
|
+
### v1.0.1
|
|
673
|
+
- Migrated to ESM-only package
|
|
674
|
+
- Added PostgreSQL version control with Git-like architecture
|
|
675
|
+
- Added file history endpoint
|
|
676
|
+
- Improved database connection handling with `postgres` package
|
|
677
|
+
- Added support for Supabase and other remote PostgreSQL databases
|
|
678
|
+
- Added automatic schema migrations
|
|
679
|
+
- Flexible DELETE endpoint (supports query params or body)
|
|
680
|
+
- Built-in JSON body parser middleware
|
|
681
|
+
|
|
247
682
|
---
|
|
248
683
|
|
|
249
684
|
Made with ❤️ for markdown lovers everywhere
|