@notehub.md/cli 0.1.9 → 0.1.11
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/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +13 -1
- package/dist/commands/create.js.map +1 -1
- package/package.json +2 -1
- package/templates/PLUGIN_GUIDE.md +21 -22
- package/templates/PLUGIN_GUIDE_RU.md +22 -21
- package/templates/docs/en/01-getting-started.md +207 -0
- package/templates/docs/en/02-architecture.md +228 -0
- package/templates/docs/en/03-api-reference.md +747 -0
- package/templates/docs/en/04-widgets.md +318 -0
- package/templates/docs/en/05-settings.md +303 -0
- package/templates/docs/en/06-context-menu.md +283 -0
- package/templates/docs/en/07-examples.md +547 -0
- package/templates/docs/en/README.md +125 -0
- package/templates/docs/ru/01-getting-started.md +207 -0
- package/templates/docs/ru/02-architecture.md +228 -0
- package/templates/docs/ru/03-api-reference.md +747 -0
- package/templates/docs/ru/04-widgets.md +289 -0
- package/templates/docs/ru/05-settings.md +303 -0
- package/templates/docs/ru/06-context-menu.md +283 -0
- package/templates/docs/ru/07-examples.md +547 -0
- package/templates/docs/ru/README.md +125 -0
- package/templates/docs.html +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAYH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAYH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAoGzE"}
|
package/dist/commands/create.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* └── styles.css (optional)
|
|
17
17
|
*/
|
|
18
18
|
import chalk from 'chalk';
|
|
19
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
19
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, cpSync } from 'node:fs';
|
|
20
20
|
import { join, resolve, dirname } from 'node:path';
|
|
21
21
|
import { fileURLToPath } from 'node:url';
|
|
22
22
|
// Get templates directory path
|
|
@@ -78,6 +78,18 @@ export async function createCommand(options) {
|
|
|
78
78
|
catch {
|
|
79
79
|
console.log(chalk.yellow(' ⚠ docs/index.html (template not found)'));
|
|
80
80
|
}
|
|
81
|
+
// Copy full documentation from templates/docs
|
|
82
|
+
try {
|
|
83
|
+
const docsSrc = join(TEMPLATES_DIR, 'docs');
|
|
84
|
+
const docsDest = join(targetDir, 'docs');
|
|
85
|
+
if (existsSync(docsSrc)) {
|
|
86
|
+
cpSync(docsSrc, docsDest, { recursive: true });
|
|
87
|
+
console.log(chalk.green(' ✓ docs/ (bundled documentation)'));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
console.log(chalk.yellow(' ⚠ Failed to copy bundled docs'));
|
|
92
|
+
}
|
|
81
93
|
// Print next steps
|
|
82
94
|
console.log(chalk.green('\n✓ Plugin created successfully!\n'));
|
|
83
95
|
console.log(chalk.white('Next steps:'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@notehub.md/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "CLI tool for building Notehub plugins",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"templates"
|
|
34
34
|
],
|
|
35
35
|
"scripts": {
|
|
36
|
+
"prebuild": "node scripts/copy-docs.js",
|
|
36
37
|
"build": "tsc",
|
|
37
38
|
"dev": "tsc --watch",
|
|
38
39
|
"clean": "rimraf dist"
|
|
@@ -276,19 +276,18 @@ const theme = await ctx.invokeApi<string>('theme:get-current');
|
|
|
276
276
|
const themes = await ctx.invokeApi<string[]>('theme:list');
|
|
277
277
|
```
|
|
278
278
|
|
|
279
|
-
## Editor
|
|
279
|
+
## Editor Portal API
|
|
280
280
|
|
|
281
281
|
```typescript
|
|
282
|
-
// Register widget
|
|
283
|
-
await ctx.invokeApi(
|
|
284
|
-
'
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
);
|
|
282
|
+
// Register portal (inline widget)
|
|
283
|
+
await ctx.invokeApi('editor:register-portal', {
|
|
284
|
+
id: 'my-plugin:progress-bar',
|
|
285
|
+
regex: /\[progress:(\d+)\]/g,
|
|
286
|
+
component: ProgressBarComponent
|
|
287
|
+
});
|
|
289
288
|
|
|
290
|
-
// Unregister (optional - auto-cleaned)
|
|
291
|
-
await ctx.invokeApi('editor:unregister-
|
|
289
|
+
// Unregister (optional - auto-cleaned on plugin unload)
|
|
290
|
+
await ctx.invokeApi('editor:unregister-portal', 'my-plugin:progress-bar');
|
|
292
291
|
```
|
|
293
292
|
|
|
294
293
|
## Settings API
|
|
@@ -407,14 +406,15 @@ const ProgressBar: React.FC<{ match: RegExpExecArray }> = ({ match }) => {
|
|
|
407
406
|
);
|
|
408
407
|
};
|
|
409
408
|
|
|
409
|
+
// Plugin
|
|
410
410
|
export default class ProgressBarPlugin extends NotehubPlugin {
|
|
411
411
|
async onload(ctx: PluginContext): Promise<void> {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
'progress-bar',
|
|
415
|
-
/\[progress:(\d+)\]/g,
|
|
416
|
-
ProgressBar
|
|
417
|
-
);
|
|
412
|
+
// Match: [progress:XX] where XX is a number
|
|
413
|
+
await ctx.invokeApi('editor:register-portal', {
|
|
414
|
+
id: 'progress-bar',
|
|
415
|
+
regex: /\[progress:(\d+)\]/g,
|
|
416
|
+
component: ProgressBar
|
|
417
|
+
});
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
async onunload(): Promise<void> {}
|
|
@@ -523,12 +523,11 @@ const WordCounter: React.FC<{ match: RegExpExecArray }> = ({ match }) => {
|
|
|
523
523
|
};
|
|
524
524
|
|
|
525
525
|
// Register with pattern: {{count: your text here}}
|
|
526
|
-
await ctx.invokeApi(
|
|
527
|
-
'
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
);
|
|
526
|
+
await ctx.invokeApi('editor:register-portal', {
|
|
527
|
+
id: 'word-counter',
|
|
528
|
+
regex: /\{\{count:\s*(.+?)\}\}/g,
|
|
529
|
+
component: WordCounter
|
|
530
|
+
});
|
|
532
531
|
```
|
|
533
532
|
|
|
534
533
|
## Full-Featured Plugin
|
|
@@ -276,19 +276,18 @@ const theme = await ctx.invokeApi<string>('theme:get-current');
|
|
|
276
276
|
const themes = await ctx.invokeApi<string[]>('theme:list');
|
|
277
277
|
```
|
|
278
278
|
|
|
279
|
-
## Editor
|
|
279
|
+
## Editor Portal API
|
|
280
280
|
|
|
281
281
|
```typescript
|
|
282
|
-
// Регистрация
|
|
283
|
-
await ctx.invokeApi(
|
|
284
|
-
'
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
);
|
|
282
|
+
// Регистрация портала (инлайн-виджета)
|
|
283
|
+
await ctx.invokeApi('editor:register-portal', {
|
|
284
|
+
id: 'my-plugin:progress-bar',
|
|
285
|
+
regex: /\[progress:(\d+)\]/g,
|
|
286
|
+
component: ProgressBarComponent
|
|
287
|
+
});
|
|
289
288
|
|
|
290
289
|
// Отмена регистрации (опционально - очищается автоматически)
|
|
291
|
-
await ctx.invokeApi('editor:unregister-
|
|
290
|
+
await ctx.invokeApi('editor:unregister-portal', 'my-plugin:progress-bar');
|
|
292
291
|
```
|
|
293
292
|
|
|
294
293
|
## Settings API
|
|
@@ -407,14 +406,17 @@ const ProgressBar: React.FC<{ match: RegExpExecArray }> = ({ match }) => {
|
|
|
407
406
|
);
|
|
408
407
|
};
|
|
409
408
|
|
|
409
|
+
// Плагин
|
|
410
410
|
export default class ProgressBarPlugin extends NotehubPlugin {
|
|
411
411
|
async onload(ctx: PluginContext): Promise<void> {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
'progress-bar',
|
|
415
|
-
/\[progress:(\d+)\]/g,
|
|
416
|
-
ProgressBar
|
|
417
|
-
);
|
|
412
|
+
// Совпадение: [progress:XX] где XX — число
|
|
413
|
+
await ctx.invokeApi('editor:register-portal', {
|
|
414
|
+
id: 'progress-bar',
|
|
415
|
+
regex: /\[progress:(\d+)\]/g,
|
|
416
|
+
component: ProgressBar
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
await ctx.invokeApi('logger:info', 'ProgressBar', 'Портал зарегистрирован');
|
|
418
420
|
}
|
|
419
421
|
|
|
420
422
|
async onunload(): Promise<void> {}
|
|
@@ -523,12 +525,11 @@ const WordCounter: React.FC<{ match: RegExpExecArray }> = ({ match }) => {
|
|
|
523
525
|
};
|
|
524
526
|
|
|
525
527
|
// Регистрация с паттерном: {{count: ваш текст здесь}}
|
|
526
|
-
await ctx.invokeApi(
|
|
527
|
-
'
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
);
|
|
528
|
+
await ctx.invokeApi('editor:register-portal', {
|
|
529
|
+
id: 'word-counter',
|
|
530
|
+
regex: /\{\{count:\s*(.+?)\}\}/g,
|
|
531
|
+
component: WordCounter
|
|
532
|
+
});
|
|
532
533
|
```
|
|
533
534
|
|
|
534
535
|
## Полноценный плагин
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide will walk you through creating your first Notehub.md plugin.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- **Node.js** v18+ with npm/pnpm
|
|
8
|
+
- **TypeScript** (recommended, but JavaScript works too)
|
|
9
|
+
- **Bundler**: esbuild, Vite, or Rollup
|
|
10
|
+
- A Notehub.md vault to test in
|
|
11
|
+
|
|
12
|
+
## Plugin Structure
|
|
13
|
+
|
|
14
|
+
Every plugin needs at minimum:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
my-plugin/
|
|
18
|
+
├── manifest.json # Plugin metadata (required)
|
|
19
|
+
├── main.js # Entry point (compiled)
|
|
20
|
+
└── src/ # Source files (optional)
|
|
21
|
+
└── index.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## manifest.json
|
|
25
|
+
|
|
26
|
+
The manifest describes your plugin to Notehub:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"id": "my-awesome-plugin",
|
|
31
|
+
"name": "My Awesome Plugin",
|
|
32
|
+
"version": "1.0.0",
|
|
33
|
+
"main": "main.js",
|
|
34
|
+
"dependencies": []
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Field | Required | Description |
|
|
39
|
+
|-------|----------|-------------|
|
|
40
|
+
| `id` | ✅ | Unique identifier (lowercase, hyphens allowed) |
|
|
41
|
+
| `name` | ✅ | Human-readable display name |
|
|
42
|
+
| `version` | ✅ | Semantic version (e.g., `1.0.0`) |
|
|
43
|
+
| `main` | ❌ | Entry point file, defaults to `main.js` |
|
|
44
|
+
| `dependencies` | ❌ | Array of internal plugin IDs this plugin requires |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Option 1: Plugin Generator (Internal Plugins)
|
|
49
|
+
|
|
50
|
+
If you're developing a plugin **inside the Notehub monorepo**, use the generator:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pnpm gen:plugin
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This interactive CLI will:
|
|
57
|
+
1. ✔ Ask for a plugin name (kebab-case)
|
|
58
|
+
2. ✔ Let you choose a category (`system`, `ui`, `features`)
|
|
59
|
+
3. ✔ Generate the full plugin structure with all boilerplate
|
|
60
|
+
|
|
61
|
+
**Generated files:**
|
|
62
|
+
- `package.json` — Package config with `@notehub/core` dependency
|
|
63
|
+
- `tsconfig.json` — TypeScript config extending base
|
|
64
|
+
- `manifest.json` — Plugin metadata
|
|
65
|
+
- `src/index.ts` — Plugin class implementing `IPlugin`
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Option 2: Manual Setup (External Plugins)
|
|
70
|
+
|
|
71
|
+
For plugins that live **outside the monorepo** and load at runtime from a vault:
|
|
72
|
+
|
|
73
|
+
### Step 1: Create the folder structure
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
mkdir my-plugin
|
|
77
|
+
cd my-plugin
|
|
78
|
+
npm init -y
|
|
79
|
+
npm install @notehub/api typescript esbuild --save-dev
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Step 2: Create manifest.json
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"id": "hello-world",
|
|
87
|
+
"name": "Hello World",
|
|
88
|
+
"version": "1.0.0"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Step 3: Create src/index.ts
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { NotehubPlugin, PluginContext } from '@notehub/api';
|
|
96
|
+
|
|
97
|
+
export default class HelloWorldPlugin extends NotehubPlugin {
|
|
98
|
+
async onload(ctx: PluginContext): Promise<void> {
|
|
99
|
+
// Log a message when plugin loads
|
|
100
|
+
await ctx.invokeApi('logger:info', 'HelloWorld', 'Hello from my plugin!');
|
|
101
|
+
|
|
102
|
+
// Register a custom API
|
|
103
|
+
ctx.registerApi('hello:say', (message: string) => {
|
|
104
|
+
console.log(`[HelloWorld] ${message}`);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Subscribe to file selection events
|
|
108
|
+
ctx.subscribe<{ path: string }>('explorer:file-selected', (payload) => {
|
|
109
|
+
console.log('File selected:', payload.path);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async onunload(): Promise<void> {
|
|
114
|
+
// Nothing to do - cleanup is automatic!
|
|
115
|
+
console.log('HelloWorld plugin unloaded');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 4: Create tsconfig.json
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"compilerOptions": {
|
|
125
|
+
"target": "ES2020",
|
|
126
|
+
"module": "ESNext",
|
|
127
|
+
"moduleResolution": "bundler",
|
|
128
|
+
"lib": ["ES2020", "DOM"],
|
|
129
|
+
"strict": true,
|
|
130
|
+
"esModuleInterop": true,
|
|
131
|
+
"skipLibCheck": true,
|
|
132
|
+
"declaration": false,
|
|
133
|
+
"outDir": "./dist"
|
|
134
|
+
},
|
|
135
|
+
"include": ["src/**/*"]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Step 5: Create build script
|
|
140
|
+
|
|
141
|
+
Add to `package.json`:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"scripts": {
|
|
146
|
+
"build": "esbuild src/index.ts --bundle --format=esm --outfile=main.js --external:@notehub/api --external:react"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Step 6: Build and install
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm run build
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Copy the folder to your vault:
|
|
158
|
+
```
|
|
159
|
+
MyVault/.notehub/plugins/hello-world/
|
|
160
|
+
├── manifest.json
|
|
161
|
+
└── main.js
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Step 7: Test
|
|
165
|
+
|
|
166
|
+
1. Open Notehub.md with your vault
|
|
167
|
+
2. Your plugin loads automatically!
|
|
168
|
+
3. Check the console for "Hello from my plugin!"
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Important: External Dependencies
|
|
173
|
+
|
|
174
|
+
Your plugin runs in a **shared scope** with Notehub. These packages are provided by the host:
|
|
175
|
+
|
|
176
|
+
| Package | Description |
|
|
177
|
+
|---------|-------------|
|
|
178
|
+
| `@notehub/api` | Plugin API (`NotehubPlugin`, `PluginContext`) |
|
|
179
|
+
| `react` | React library |
|
|
180
|
+
| `react-dom` | React DOM renderer |
|
|
181
|
+
|
|
182
|
+
**Mark these as external** in your bundler config to avoid duplicating them!
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Hot Reload
|
|
187
|
+
|
|
188
|
+
Notehub watches the `.notehub/plugins/` directory. When you update your plugin:
|
|
189
|
+
|
|
190
|
+
1. The old version is automatically unloaded
|
|
191
|
+
2. The new version is loaded
|
|
192
|
+
3. All your API registrations are cleaned up automatically!
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Debugging Tips
|
|
197
|
+
|
|
198
|
+
1. **Open DevTools** (Ctrl+Shift+I) to see console logs
|
|
199
|
+
2. **Use `logger:info`** API for structured logging
|
|
200
|
+
3. **Check the Synapse plugin** logs for load/unload events
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Next Steps
|
|
205
|
+
|
|
206
|
+
- Read **[Architecture](02-architecture.md)** to understand the plugin lifecycle
|
|
207
|
+
- Explore the **[API Reference](03-api-reference.md)** for all available methods
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Plugin Architecture
|
|
2
|
+
|
|
3
|
+
This document explains how Notehub.md plugins work under the hood.
|
|
4
|
+
|
|
5
|
+
## Microkernel Architecture
|
|
6
|
+
|
|
7
|
+
Notehub.md follows a **microkernel** design where the core is minimal and all functionality comes from plugins:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ NotehubCore │
|
|
12
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
|
13
|
+
│ │ EventBus │ │ ApiBus │ │ Plugin Registry │ │
|
|
14
|
+
│ │ (pub/sub) │ │ (RPC calls) │ │ (lifecycle mgmt) │ │
|
|
15
|
+
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
|
|
16
|
+
└─────────────────────────────────────────────────────────────┘
|
|
17
|
+
▲ ▲ ▲
|
|
18
|
+
│ │ │
|
|
19
|
+
┌────┴───┐ ┌─────┴────┐ ┌─────┴────┐
|
|
20
|
+
│ Logger │ │ Editor │ │ Explorer │
|
|
21
|
+
│ Plugin │ │ Plugin │ │ Plugin │
|
|
22
|
+
└────────┘ └──────────┘ └──────────┘
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Plugin Types
|
|
26
|
+
|
|
27
|
+
### Internal Plugins (IPlugin)
|
|
28
|
+
|
|
29
|
+
Core features implement the `IPlugin` interface directly:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
interface IPlugin {
|
|
33
|
+
readonly manifest: PluginManifest;
|
|
34
|
+
load(app: NotehubCore): Promise<void> | void;
|
|
35
|
+
onReady?(app: NotehubCore): Promise<void> | void;
|
|
36
|
+
unload(app: NotehubCore): Promise<void> | void;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### External Plugins (NotehubPlugin)
|
|
41
|
+
|
|
42
|
+
Your plugins extend `NotehubPlugin` and use `PluginContext`:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
abstract class NotehubPlugin {
|
|
46
|
+
abstract onload(ctx: PluginContext): Promise<void> | void;
|
|
47
|
+
abstract onunload(): Promise<void> | void;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The key difference: **external plugins get automatic cleanup** via `PluginContext`!
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Plugin Lifecycle
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
┌──────────────────────────────────────────────────────────┐
|
|
59
|
+
│ Plugin Lifecycle │
|
|
60
|
+
├──────────────────────────────────────────────────────────┤
|
|
61
|
+
│ │
|
|
62
|
+
│ 1. DISCOVERY │
|
|
63
|
+
│ └─ Synapse scans .notehub/plugins/ folder │
|
|
64
|
+
│ └─ Reads manifest.json for each plugin │
|
|
65
|
+
│ │
|
|
66
|
+
│ 2. LOADING │
|
|
67
|
+
│ └─ SystemJS imports the main.js module │
|
|
68
|
+
│ └─ Plugin class is instantiated │
|
|
69
|
+
│ └─ PluginContext is created (for external plugins) │
|
|
70
|
+
│ │
|
|
71
|
+
│ 3. INITIALIZATION (onload) │
|
|
72
|
+
│ └─ Plugin registers APIs │
|
|
73
|
+
│ └─ Plugin subscribes to events │
|
|
74
|
+
│ └─ Plugin sets up UI components │
|
|
75
|
+
│ │
|
|
76
|
+
│ 4. RUNNING │
|
|
77
|
+
│ └─ Plugin responds to events │
|
|
78
|
+
│ └─ Plugin handles API calls │
|
|
79
|
+
│ │
|
|
80
|
+
│ 5. UNLOADING (onunload) │
|
|
81
|
+
│ └─ Plugin performs manual cleanup (optional) │
|
|
82
|
+
│ └─ PluginContext auto-cleans registrations │
|
|
83
|
+
│ └─ SystemJS module is unregistered │
|
|
84
|
+
│ │
|
|
85
|
+
└──────────────────────────────────────────────────────────┘
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## PluginContext
|
|
91
|
+
|
|
92
|
+
The `PluginContext` is your gateway to the Notehub ecosystem:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface PluginContext {
|
|
96
|
+
// Register an API that other plugins can call
|
|
97
|
+
registerApi(name: string, handler: (...args: unknown[]) => unknown): void;
|
|
98
|
+
|
|
99
|
+
// Call an API registered by any plugin
|
|
100
|
+
invokeApi<T>(name: string, ...args: unknown[]): Promise<T>;
|
|
101
|
+
|
|
102
|
+
// Subscribe to application events
|
|
103
|
+
subscribe<T>(event: string, handler: (payload: T) => void): void;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Auto-Cleanup Magic
|
|
108
|
+
|
|
109
|
+
When your plugin is unloaded, `PluginContext` automatically:
|
|
110
|
+
|
|
111
|
+
- ✅ Unregisters all APIs you registered
|
|
112
|
+
- ✅ Unsubscribes from all events
|
|
113
|
+
- ✅ Removes editor widgets you registered
|
|
114
|
+
- ✅ Removes settings tabs/groups/items you added
|
|
115
|
+
|
|
116
|
+
**You don't need to manually clean these up!**
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Communication Patterns
|
|
121
|
+
|
|
122
|
+
### 1. EventBus (Pub/Sub)
|
|
123
|
+
|
|
124
|
+
For **broadcasting** information to multiple listeners:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Subscribe to an event
|
|
128
|
+
ctx.subscribe<{ path: string }>('explorer:file-selected', (payload) => {
|
|
129
|
+
console.log('File selected:', payload.path);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Events are emitted by plugins internally
|
|
133
|
+
// External plugins can only subscribe, not emit
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Common events:
|
|
137
|
+
- `explorer:file-selected` - User clicked a file
|
|
138
|
+
- `editor:file-opened` - File content loaded
|
|
139
|
+
- `editor:file-closed` - Editor cleared
|
|
140
|
+
- `vault:opened` - Vault was opened
|
|
141
|
+
- `vault:closed` - Vault was closed
|
|
142
|
+
|
|
143
|
+
### 2. ApiBus (RPC)
|
|
144
|
+
|
|
145
|
+
For **direct method calls** between plugins:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Register an API
|
|
149
|
+
ctx.registerApi('my-plugin:calculate', (a: number, b: number) => a + b);
|
|
150
|
+
|
|
151
|
+
// Invoke someone else's API
|
|
152
|
+
const result = await ctx.invokeApi<number>('my-plugin:calculate', 5, 3);
|
|
153
|
+
// result = 8
|
|
154
|
+
|
|
155
|
+
// All core APIs are available via invokeApi
|
|
156
|
+
const content = await ctx.invokeApi<string>('fs:read-text-file', '/path/to/file.md');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Dependency Resolution
|
|
162
|
+
|
|
163
|
+
Plugins can declare dependencies in `manifest.json`:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"id": "my-plugin",
|
|
168
|
+
"dependencies": ["nh.features.editor"]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The bootloader ensures dependencies load before your plugin.
|
|
173
|
+
|
|
174
|
+
**Note:** For external plugins, core plugins are always available. You typically don't need to declare dependencies unless you depend on another external plugin.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Hot Reload
|
|
179
|
+
|
|
180
|
+
Notehub watches the plugins folder. When a file changes:
|
|
181
|
+
|
|
182
|
+
1. **Detect** - File watcher triggers on `.js` or `manifest.json` change
|
|
183
|
+
2. **Unload** - Old plugin version is unloaded (calls `onunload()`)
|
|
184
|
+
3. **Cleanup** - PluginContext removes all registrations
|
|
185
|
+
4. **Reload** - New version is loaded (calls `onload()`)
|
|
186
|
+
|
|
187
|
+
This enables **rapid development** without restarting Notehub!
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Best Practices
|
|
192
|
+
|
|
193
|
+
### 1. Namespace your APIs
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// ✅ Good - namespaced
|
|
197
|
+
ctx.registerApi('my-plugin:do-something', handler);
|
|
198
|
+
|
|
199
|
+
// ❌ Bad - may conflict
|
|
200
|
+
ctx.registerApi('do-something', handler);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 2. Handle errors gracefully
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
async onload(ctx: PluginContext): Promise<void> {
|
|
207
|
+
try {
|
|
208
|
+
const data = await ctx.invokeApi('fs:read-text-file', '/config.json');
|
|
209
|
+
// ...
|
|
210
|
+
} catch (error) {
|
|
211
|
+
await ctx.invokeApi('logger:error', 'MyPlugin', `Failed to load: ${error}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 3. Use TypeScript for better IntelliSense
|
|
217
|
+
|
|
218
|
+
The `@notehub/api` package includes full type definitions for all APIs.
|
|
219
|
+
|
|
220
|
+
### 4. Keep onload() fast
|
|
221
|
+
|
|
222
|
+
Don't block initialization with heavy work. Use async patterns or defer work.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Next Steps
|
|
227
|
+
|
|
228
|
+
See the complete **[API Reference](03-api-reference.md)** for all available methods.
|