@nuxtblog/plugin-sdk 0.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 +308 -0
- package/index.d.ts +642 -0
- package/package.json +30 -0
- package/tsconfig.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# @nuxtblog/plugin-sdk
|
|
2
|
+
|
|
3
|
+
TypeScript type definitions and base `tsconfig` for [nuxtblog](https://github.com/nuxtblog/nuxtblog) plugins.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D @nuxtblog/plugin-sdk
|
|
9
|
+
# or
|
|
10
|
+
npm install -D @nuxtblog/plugin-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### tsconfig.json
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"extends": "@nuxtblog/plugin-sdk",
|
|
20
|
+
"include": ["src"]
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This gives you strict TypeScript compiler options and the global `nuxtblog` object with full type coverage.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Plugin manifest (package.json)
|
|
29
|
+
|
|
30
|
+
Every plugin declares its metadata and permissions in `package.json` under the `"plugin"` field.
|
|
31
|
+
Capabilities must be explicitly declared — only declared APIs are injected into the plugin VM.
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"name": "owner/my-plugin",
|
|
36
|
+
"version": "1.0.0",
|
|
37
|
+
"description": "What it does",
|
|
38
|
+
"author": "owner",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"plugin": {
|
|
41
|
+
"title": "My Plugin",
|
|
42
|
+
"icon": "i-tabler-plug",
|
|
43
|
+
"entry": "dist/index.js",
|
|
44
|
+
"priority": 10,
|
|
45
|
+
"capabilities": {
|
|
46
|
+
"http": { "allow": ["hooks.slack.com"], "timeout_ms": 5000 },
|
|
47
|
+
"store": { "read": true, "write": true }
|
|
48
|
+
},
|
|
49
|
+
"settings": [
|
|
50
|
+
{ "key": "webhook_url", "label": "Slack Webhook URL", "type": "string", "required": true }
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Plugin API
|
|
59
|
+
|
|
60
|
+
### `nuxtblog.filter` — synchronous interceptor
|
|
61
|
+
|
|
62
|
+
Runs **before** data is written to the database. Modify `ctx.data` or call `ctx.abort()` to cancel.
|
|
63
|
+
HTTP requests are **not allowed** inside filter handlers.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// src/index.ts
|
|
67
|
+
|
|
68
|
+
nuxtblog.filter('post.create', (ctx) => {
|
|
69
|
+
if (!ctx.data.title) {
|
|
70
|
+
ctx.abort('title is required')
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
ctx.data.title = ctx.data.title.trim()
|
|
74
|
+
// ctx.next() is optional — the chain continues unless abort() is called
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
nuxtblog.filter('content.render', (ctx) => {
|
|
78
|
+
// ctx.input — read-only snapshot before the chain (for diff/audit)
|
|
79
|
+
// ctx.data — mutable, changes are returned to the caller
|
|
80
|
+
// ctx.meta — shared KV across all plugins in the same chain
|
|
81
|
+
ctx.data.content = ctx.data.content.replace(/\bfoo\b/g, 'bar')
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `nuxtblog.on` — async event handler
|
|
86
|
+
|
|
87
|
+
Runs **after** the operation completes. HTTP requests are allowed.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
nuxtblog.on('post.published', (data) => {
|
|
91
|
+
const url = nuxtblog.settings.get('webhook_url') as string
|
|
92
|
+
nuxtblog.http.fetch(url, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
body: { text: `New post: ${data.title}` },
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
nuxtblog.on('user.registered', (data) => {
|
|
99
|
+
nuxtblog.log.info(`New user: ${data.username} (${data.email})`)
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### `nuxtblog.http.fetch` — synchronous HTTP
|
|
104
|
+
|
|
105
|
+
Available when `capabilities.http` is declared. Returns immediately (not a Promise).
|
|
106
|
+
Blocked inside `filter` handlers.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const res = nuxtblog.http.fetch<{ id: string }>('https://api.example.com/create', {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
body: { title: 'Hello' },
|
|
112
|
+
headers: { Authorization: 'Bearer token' },
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
if (res.ok) {
|
|
116
|
+
nuxtblog.log.info('created: ' + res.body.id)
|
|
117
|
+
} else {
|
|
118
|
+
nuxtblog.log.error(res.error ?? `HTTP ${res.status}`)
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `nuxtblog.store` — persistent key-value store
|
|
123
|
+
|
|
124
|
+
Available when `capabilities.store` is declared. Keys are namespaced per plugin.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
nuxtblog.store.set('last_run', new Date().toISOString())
|
|
128
|
+
const last = nuxtblog.store.get('last_run') // unknown
|
|
129
|
+
nuxtblog.store.delete('last_run')
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `nuxtblog.settings.get` — admin-configured settings
|
|
133
|
+
|
|
134
|
+
Always available. Cached for 30 seconds.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const apiKey = nuxtblog.settings.get('api_key') as string
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### `nuxtblog.log` — server logging
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
nuxtblog.log.info('hello')
|
|
144
|
+
nuxtblog.log.warn('something looks off')
|
|
145
|
+
nuxtblog.log.error('this failed')
|
|
146
|
+
nuxtblog.log.debug('verbose details')
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Declarative webhooks (no JS needed)
|
|
152
|
+
|
|
153
|
+
Simple outbound notifications can be declared in the manifest instead of writing JS.
|
|
154
|
+
|
|
155
|
+
**Never hardcode secrets in the manifest.** Use `{{settings.key}}` placeholders in `url`
|
|
156
|
+
and header values — they are resolved at dispatch time from admin-configured settings:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"plugin": {
|
|
161
|
+
"settings": [
|
|
162
|
+
{ "key": "webhook_url", "label": "Webhook URL", "type": "string", "placeholder": "https://hooks.slack.com/..." },
|
|
163
|
+
{ "key": "webhook_token", "label": "Webhook Token", "type": "password", "placeholder": "xoxb-..." }
|
|
164
|
+
],
|
|
165
|
+
"webhooks": [
|
|
166
|
+
{
|
|
167
|
+
"url": "{{settings.webhook_url}}",
|
|
168
|
+
"events": ["post.published", "comment.created"],
|
|
169
|
+
"headers": { "Authorization": "Bearer {{settings.webhook_token}}" }
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Event patterns: `"post.*"` matches all post events; `"*"` matches everything.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Declarative pipelines (multi-step async workflows)
|
|
181
|
+
|
|
182
|
+
For multi-step workflows with conditionals and retries, declare a pipeline in the manifest.
|
|
183
|
+
JS functions exported at module scope are called by name.
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"plugin": {
|
|
188
|
+
"capabilities": {
|
|
189
|
+
"http": { "allow": ["ai-api.example.com", "hooks.slack.com"] }
|
|
190
|
+
},
|
|
191
|
+
"pipelines": [
|
|
192
|
+
{
|
|
193
|
+
"name": "post-publish",
|
|
194
|
+
"trigger": "post.published",
|
|
195
|
+
"steps": [
|
|
196
|
+
{
|
|
197
|
+
"type": "js",
|
|
198
|
+
"name": "Generate summary",
|
|
199
|
+
"fn": "generateSummary",
|
|
200
|
+
"timeout_ms": 8000,
|
|
201
|
+
"retry": 1
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"type": "condition",
|
|
205
|
+
"name": "Branch by category",
|
|
206
|
+
"if": "ctx.data.category === 'tech'",
|
|
207
|
+
"then": [
|
|
208
|
+
{ "type": "webhook", "name": "Post to Twitter", "url": "https://api.twitter.com/..." }
|
|
209
|
+
],
|
|
210
|
+
"else": [
|
|
211
|
+
{ "type": "js", "name": "Notify Slack", "fn": "notifySlack" }
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
// src/index.ts — functions called by pipeline steps must be exported at module scope
|
|
223
|
+
|
|
224
|
+
function generateSummary(ctx: StepContext) {
|
|
225
|
+
const res = nuxtblog.http.fetch<{ summary: string }>('https://ai-api.example.com/summarize', {
|
|
226
|
+
method: 'POST',
|
|
227
|
+
body: { content: ctx.data.content as string },
|
|
228
|
+
})
|
|
229
|
+
if (res.ok) {
|
|
230
|
+
ctx.data.excerpt = res.body.summary
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function notifySlack(ctx: StepContext) {
|
|
235
|
+
nuxtblog.http.fetch('https://hooks.slack.com/services/xxx', {
|
|
236
|
+
method: 'POST',
|
|
237
|
+
body: { text: `New post: ${ctx.data.title}` },
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Step types:
|
|
243
|
+
- `"js"` — call an exported JS function; supports `timeout_ms` and `retry`
|
|
244
|
+
- `"webhook"` — POST the event payload to a URL; supports `timeout_ms` and `retry`
|
|
245
|
+
- `"condition"` — evaluate a JS boolean expression, branch to `then` or `else`
|
|
246
|
+
|
|
247
|
+
Retry backoff: 200 ms → 400 ms → 800 ms … capped at 8 s.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Event reference
|
|
252
|
+
|
|
253
|
+
### Fire-and-forget events (`nuxtblog.on`)
|
|
254
|
+
|
|
255
|
+
| Event | Payload type |
|
|
256
|
+
|-------|-------------|
|
|
257
|
+
| `post.created` | `PostCreatedPayload` |
|
|
258
|
+
| `post.updated` | `PostUpdatedPayload` |
|
|
259
|
+
| `post.published` | `PostPublishedPayload` |
|
|
260
|
+
| `post.deleted` | `PostDeletedPayload` |
|
|
261
|
+
| `post.viewed` | `PostViewedPayload` |
|
|
262
|
+
| `comment.created` | `CommentCreatedPayload` |
|
|
263
|
+
| `comment.deleted` | `CommentDeletedPayload` |
|
|
264
|
+
| `comment.status_changed` | `CommentStatusChangedPayload` |
|
|
265
|
+
| `comment.approved` | `CommentApprovedPayload` |
|
|
266
|
+
| `user.registered` | `UserRegisteredPayload` |
|
|
267
|
+
| `user.updated` | `UserUpdatedPayload` |
|
|
268
|
+
| `user.deleted` | `UserDeletedPayload` |
|
|
269
|
+
| `user.followed` | `UserFollowedPayload` |
|
|
270
|
+
| `user.login` | `UserLoginPayload` |
|
|
271
|
+
| `user.logout` | `UserLogoutPayload` |
|
|
272
|
+
| `media.uploaded` | `MediaUploadedPayload` |
|
|
273
|
+
| `media.deleted` | `MediaDeletedPayload` |
|
|
274
|
+
| `taxonomy.created` | `TaxonomyCreatedPayload` |
|
|
275
|
+
| `taxonomy.deleted` | `TaxonomyDeletedPayload` |
|
|
276
|
+
| `term.created` | `TermCreatedPayload` |
|
|
277
|
+
| `term.deleted` | `TermDeletedPayload` |
|
|
278
|
+
| `reaction.added` | `ReactionPayload` |
|
|
279
|
+
| `reaction.removed` | `ReactionPayload` |
|
|
280
|
+
| `checkin.done` | `CheckinPayload` |
|
|
281
|
+
| `option.updated` | `OptionUpdatedPayload` |
|
|
282
|
+
| `plugin.installed` | `PluginInstalledPayload` |
|
|
283
|
+
| `plugin.uninstalled` | `PluginUninstalledPayload` |
|
|
284
|
+
|
|
285
|
+
### Filter events (`nuxtblog.filter`)
|
|
286
|
+
|
|
287
|
+
| Event | `ctx.data` type | Notes |
|
|
288
|
+
|-------|----------------|-------|
|
|
289
|
+
| `post.create` | `FilterPostCreateData` | |
|
|
290
|
+
| `post.update` | `FilterPostUpdateData` | Only updated fields are present |
|
|
291
|
+
| `post.delete` | `FilterPostDeleteData` | `abort()` cancels the deletion |
|
|
292
|
+
| `comment.create` | `FilterCommentCreateData` | |
|
|
293
|
+
| `comment.delete` | `FilterCommentDeleteData` | `abort()` cancels the deletion |
|
|
294
|
+
| `term.create` | `FilterTermCreateData` | |
|
|
295
|
+
| `user.register` | `FilterUserRegisterData` | |
|
|
296
|
+
| `user.update` | `FilterUserUpdateData` | Only updated fields are present |
|
|
297
|
+
| `media.upload` | `FilterMediaUploadData` | |
|
|
298
|
+
| `content.render` | `FilterContentRenderData` | Modify `ctx.data.content` to change what readers see |
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Publishing a plugin
|
|
303
|
+
|
|
304
|
+
See the [nuxtblog plugin registry](https://github.com/nuxtblog/registry) for how to submit your plugin to the marketplace.
|
|
305
|
+
|
|
306
|
+
## License
|
|
307
|
+
|
|
308
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nuxtblog/plugin-sdk — Type declarations for nuxtblog plugins
|
|
3
|
+
*
|
|
4
|
+
* ─── Manifest (package.json "plugin" field) ──────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* {
|
|
7
|
+
* "name": "owner/repo", // required, unique plugin ID
|
|
8
|
+
* "title": "My Plugin",
|
|
9
|
+
* "description": "...",
|
|
10
|
+
* "version": "1.0.0",
|
|
11
|
+
* "author": "owner",
|
|
12
|
+
* "icon": "i-tabler-plug", // any Tabler / Lucide icon name
|
|
13
|
+
* "entry": "dist/index.js", // bundled JS entry (default: dist/index.js)
|
|
14
|
+
* "css": ".my-class { ... }", // optional CSS injected into frontend <head>
|
|
15
|
+
* "priority": 10, // execution order: lower runs first (default: 10)
|
|
16
|
+
* "settings": [ ... ], // see SettingField below
|
|
17
|
+
* "capabilities": { // required — only declared APIs are injected
|
|
18
|
+
* "http": { "allow": ["api.example.com"], "timeout_ms": 5000 },
|
|
19
|
+
* "store": { "read": true, "write": true },
|
|
20
|
+
* "events": { "subscribe": ["post.*"] }
|
|
21
|
+
* },
|
|
22
|
+
* "webhooks": [
|
|
23
|
+
* // Declarative outbound webhooks — no JS needed.
|
|
24
|
+
* // url and header values support {{settings.key}} to read admin-configured values
|
|
25
|
+
* // at dispatch time (30-second TTL cache). Never hardcode secrets in the manifest.
|
|
26
|
+
* {
|
|
27
|
+
* "url": "{{settings.webhook_url}}",
|
|
28
|
+
* "events": ["post.*"],
|
|
29
|
+
* "headers": { "Authorization": "Bearer {{settings.webhook_token}}" }
|
|
30
|
+
* }
|
|
31
|
+
* ],
|
|
32
|
+
* "pipelines": [ // declarative multi-step async workflows
|
|
33
|
+
* {
|
|
34
|
+
* "name": "post-publish",
|
|
35
|
+
* "trigger": "post.published",
|
|
36
|
+
* "steps": [
|
|
37
|
+
* { "type": "js", "name": "Generate summary", "fn": "generateSummary", "timeout_ms": 8000, "retry": 1 },
|
|
38
|
+
* {
|
|
39
|
+
* // webhook step url also supports {{settings.key}}
|
|
40
|
+
* "type": "webhook", "name": "Notify Slack",
|
|
41
|
+
* "url": "{{settings.slack_webhook_url}}", "headers": {}
|
|
42
|
+
* },
|
|
43
|
+
* {
|
|
44
|
+
* "type": "condition", "name": "Branch by category",
|
|
45
|
+
* "if": "ctx.data.category === 'tech'",
|
|
46
|
+
* "then": [ { "type": "js", "name": "Tweet it", "fn": "postTweet" } ],
|
|
47
|
+
* "else": [ { "type": "js", "name": "Log skip", "fn": "logSkip" } ]
|
|
48
|
+
* }
|
|
49
|
+
* ]
|
|
50
|
+
* }
|
|
51
|
+
* ]
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* ─── Plugin API overview ─────────────────────────────────────────────────────
|
|
55
|
+
*
|
|
56
|
+
* nuxtblog.filter(event, (ctx) => { }) ← guard: sync, can abort, HTTP blocked
|
|
57
|
+
* nuxtblog.on(event, (data) => { }) ← simple response: async, HTTP allowed
|
|
58
|
+
* function myStep(ctx: StepContext) { } ← pipeline step: async, HTTP allowed
|
|
59
|
+
* manifest.webhooks ← outbound POST, no JS needed
|
|
60
|
+
* manifest.pipelines ← multi-step workflow with retry/condition
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Filter context (nuxtblog.filter handlers)
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Context passed to every `nuxtblog.filter()` handler.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* nuxtblog.filter('post.create', (ctx) => {
|
|
72
|
+
* if (ctx.data.title.length > 200) {
|
|
73
|
+
* ctx.abort('title too long')
|
|
74
|
+
* return
|
|
75
|
+
* }
|
|
76
|
+
* ctx.data.title = ctx.data.title.trim()
|
|
77
|
+
* ctx.meta.slug = ctx.data.title.toLowerCase().replace(/\s+/g, '-')
|
|
78
|
+
* ctx.next() // optional — chain continues even without it
|
|
79
|
+
* })
|
|
80
|
+
*/
|
|
81
|
+
interface PluginCtx<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
82
|
+
/** The filter event name (e.g. "post.create"). */
|
|
83
|
+
readonly event: string
|
|
84
|
+
/**
|
|
85
|
+
* Read-only snapshot of `data` taken before the filter chain started.
|
|
86
|
+
* Use it for audit / diff purposes; modifications have no effect.
|
|
87
|
+
*/
|
|
88
|
+
readonly input: Readonly<T>
|
|
89
|
+
/** Mutable payload. Modify fields here — they are persisted after the chain. */
|
|
90
|
+
data: T
|
|
91
|
+
/** Request-scoped KV store shared across all plugins in the same filter chain. */
|
|
92
|
+
meta: Record<string, unknown>
|
|
93
|
+
/**
|
|
94
|
+
* Signal that this handler is done and the chain should continue.
|
|
95
|
+
* Calling `next()` is optional — the chain always continues unless `abort()` is called.
|
|
96
|
+
*/
|
|
97
|
+
next(): void
|
|
98
|
+
/**
|
|
99
|
+
* Stop the filter chain immediately. All subsequent handlers are skipped.
|
|
100
|
+
* The operation is rejected and `reason` is surfaced to the caller.
|
|
101
|
+
*/
|
|
102
|
+
abort(reason: string): void
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Pipeline step context (pipeline "type": "js" step handlers)
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Context passed to functions called as pipeline JS steps.
|
|
111
|
+
* Unlike `PluginCtx`, this context:
|
|
112
|
+
* - lives for the entire pipeline (not just one handler)
|
|
113
|
+
* - allows `nuxtblog.http.fetch` calls
|
|
114
|
+
* - has no `input` snapshot or `next()` method
|
|
115
|
+
*
|
|
116
|
+
* Export the function at module scope — the pipeline engine looks it up by name.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* // In package.json pipeline step: { "type": "js", "fn": "generateSummary" }
|
|
120
|
+
* function generateSummary(ctx: StepContext) {
|
|
121
|
+
* const res = nuxtblog.http.fetch('https://ai-api/summarize', {
|
|
122
|
+
* method: 'POST', body: { content: ctx.data.content as string }
|
|
123
|
+
* })
|
|
124
|
+
* ctx.data.excerpt = (res.body as any).summary
|
|
125
|
+
* }
|
|
126
|
+
*/
|
|
127
|
+
interface StepContext<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
128
|
+
/** The trigger event name (e.g. "post.published"). */
|
|
129
|
+
readonly event: string
|
|
130
|
+
/** Mutable payload shared across all steps in the pipeline. */
|
|
131
|
+
data: T
|
|
132
|
+
/** Pipeline-scoped KV store; values written by earlier steps are visible to later ones. */
|
|
133
|
+
meta: Record<string, unknown>
|
|
134
|
+
/** Stop the pipeline immediately. Subsequent steps are skipped. */
|
|
135
|
+
abort(reason: string): void
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Event payloads (nuxtblog.on)
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
// ── Post ────────────────────────────────────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
interface PostCreatedPayload {
|
|
145
|
+
id: number
|
|
146
|
+
title: string
|
|
147
|
+
slug: string
|
|
148
|
+
excerpt: string
|
|
149
|
+
/** 0 = post 1 = page */
|
|
150
|
+
post_type: number
|
|
151
|
+
author_id: number
|
|
152
|
+
/** 0 = draft 1 = published 2 = trash */
|
|
153
|
+
status: number
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
interface PostUpdatedPayload {
|
|
157
|
+
id: number
|
|
158
|
+
title: string
|
|
159
|
+
slug: string
|
|
160
|
+
excerpt: string
|
|
161
|
+
post_type: number
|
|
162
|
+
author_id: number
|
|
163
|
+
status: number
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
interface PostPublishedPayload {
|
|
167
|
+
id: number
|
|
168
|
+
title: string
|
|
169
|
+
slug: string
|
|
170
|
+
excerpt: string
|
|
171
|
+
post_type: number
|
|
172
|
+
author_id: number
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
interface PostDeletedPayload {
|
|
176
|
+
id: number
|
|
177
|
+
title: string
|
|
178
|
+
slug: string
|
|
179
|
+
post_type: number
|
|
180
|
+
author_id: number
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
interface PostViewedPayload {
|
|
184
|
+
id: number
|
|
185
|
+
user_id: number
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ── Comment ──────────────────────────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
interface CommentCreatedPayload {
|
|
191
|
+
id: number
|
|
192
|
+
/** 0 = pending 1 = approved 2 = spam */
|
|
193
|
+
status: number
|
|
194
|
+
object_type: string
|
|
195
|
+
object_id: number
|
|
196
|
+
object_title: string
|
|
197
|
+
object_slug: string
|
|
198
|
+
post_author_id: number
|
|
199
|
+
/** Undefined for top-level comments */
|
|
200
|
+
parent_id?: number
|
|
201
|
+
parent_author_id: number
|
|
202
|
+
author_id: number
|
|
203
|
+
author_name: string
|
|
204
|
+
author_email: string
|
|
205
|
+
content: string
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
interface CommentDeletedPayload {
|
|
209
|
+
id: number
|
|
210
|
+
object_type: string
|
|
211
|
+
object_id: number
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
interface CommentStatusChangedPayload {
|
|
215
|
+
id: number
|
|
216
|
+
object_type: string
|
|
217
|
+
object_id: number
|
|
218
|
+
/** 0 = pending 1 = approved 2 = spam */
|
|
219
|
+
old_status: number
|
|
220
|
+
new_status: number
|
|
221
|
+
moderator_id: number
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
interface CommentApprovedPayload {
|
|
225
|
+
id: number
|
|
226
|
+
object_type: string
|
|
227
|
+
object_id: number
|
|
228
|
+
moderator_id: number
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ── User ─────────────────────────────────────────────────────────────────────
|
|
232
|
+
|
|
233
|
+
interface UserRegisteredPayload {
|
|
234
|
+
id: number
|
|
235
|
+
username: string
|
|
236
|
+
email: string
|
|
237
|
+
display_name: string
|
|
238
|
+
locale: string
|
|
239
|
+
/** 0 = subscriber 1 = contributor 2 = editor 3 = admin */
|
|
240
|
+
role: number
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
interface UserUpdatedPayload {
|
|
244
|
+
id: number
|
|
245
|
+
username: string
|
|
246
|
+
email: string
|
|
247
|
+
display_name: string
|
|
248
|
+
locale: string
|
|
249
|
+
role: number
|
|
250
|
+
/** 0 = active 1 = inactive/banned */
|
|
251
|
+
status: number
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
interface UserDeletedPayload {
|
|
255
|
+
id: number
|
|
256
|
+
username: string
|
|
257
|
+
email: string
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
interface UserFollowedPayload {
|
|
261
|
+
follower_id: number
|
|
262
|
+
follower_name: string
|
|
263
|
+
follower_avatar: string
|
|
264
|
+
following_id: number
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
interface UserLoginPayload {
|
|
268
|
+
id: number
|
|
269
|
+
username: string
|
|
270
|
+
email: string
|
|
271
|
+
role: number
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
interface UserLogoutPayload {
|
|
275
|
+
id: number
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ── Media ─────────────────────────────────────────────────────────────────────
|
|
279
|
+
|
|
280
|
+
interface MediaUploadedPayload {
|
|
281
|
+
id: number
|
|
282
|
+
uploader_id: number
|
|
283
|
+
filename: string
|
|
284
|
+
mime_type: string
|
|
285
|
+
/** bytes */
|
|
286
|
+
file_size: number
|
|
287
|
+
/** public CDN / storage URL */
|
|
288
|
+
url: string
|
|
289
|
+
category: string
|
|
290
|
+
/** 0 for non-image files */
|
|
291
|
+
width: number
|
|
292
|
+
height: number
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
interface MediaDeletedPayload {
|
|
296
|
+
id: number
|
|
297
|
+
uploader_id: number
|
|
298
|
+
filename: string
|
|
299
|
+
mime_type: string
|
|
300
|
+
category: string
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ── Taxonomy / Term ───────────────────────────────────────────────────────────
|
|
304
|
+
|
|
305
|
+
interface TaxonomyCreatedPayload {
|
|
306
|
+
id: number
|
|
307
|
+
term_id: number
|
|
308
|
+
term_name: string
|
|
309
|
+
term_slug: string
|
|
310
|
+
/** e.g. "category" | "tag" */
|
|
311
|
+
taxonomy: string
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
interface TaxonomyDeletedPayload {
|
|
315
|
+
id: number
|
|
316
|
+
term_name: string
|
|
317
|
+
term_slug: string
|
|
318
|
+
taxonomy: string
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
interface TermCreatedPayload {
|
|
322
|
+
id: number
|
|
323
|
+
name: string
|
|
324
|
+
slug: string
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
interface TermDeletedPayload {
|
|
328
|
+
id: number
|
|
329
|
+
name: string
|
|
330
|
+
slug: string
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ── Reaction / Checkin ────────────────────────────────────────────────────────
|
|
334
|
+
|
|
335
|
+
interface ReactionPayload {
|
|
336
|
+
user_id: number
|
|
337
|
+
object_type: string
|
|
338
|
+
object_id: number
|
|
339
|
+
type: "like" | "bookmark"
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
interface CheckinPayload {
|
|
343
|
+
user_id: number
|
|
344
|
+
streak: number
|
|
345
|
+
already_checked_in: boolean
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ── System ────────────────────────────────────────────────────────────────────
|
|
349
|
+
|
|
350
|
+
interface OptionUpdatedPayload {
|
|
351
|
+
key: string
|
|
352
|
+
value: unknown
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
interface PluginInstalledPayload {
|
|
356
|
+
id: string
|
|
357
|
+
title: string
|
|
358
|
+
version: string
|
|
359
|
+
author: string
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
interface PluginUninstalledPayload {
|
|
363
|
+
id: string
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
// Filter data shapes (nuxtblog.filter — ctx.data type)
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
interface FilterPostCreateData {
|
|
371
|
+
title: string
|
|
372
|
+
slug: string
|
|
373
|
+
content: string
|
|
374
|
+
excerpt: string
|
|
375
|
+
/** 0 = draft 1 = published */
|
|
376
|
+
status: number
|
|
377
|
+
[key: string]: unknown
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** Only fields being updated are present */
|
|
381
|
+
type FilterPostUpdateData = Partial<FilterPostCreateData>
|
|
382
|
+
|
|
383
|
+
interface FilterPostDeleteData {
|
|
384
|
+
id: number
|
|
385
|
+
[key: string]: unknown
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
interface FilterCommentCreateData {
|
|
389
|
+
content: string
|
|
390
|
+
author_name: string
|
|
391
|
+
author_email: string
|
|
392
|
+
[key: string]: unknown
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
interface FilterCommentDeleteData {
|
|
396
|
+
id: number
|
|
397
|
+
[key: string]: unknown
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
interface FilterTermCreateData {
|
|
401
|
+
name: string
|
|
402
|
+
slug: string
|
|
403
|
+
[key: string]: unknown
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
interface FilterUserRegisterData {
|
|
407
|
+
username: string
|
|
408
|
+
email: string
|
|
409
|
+
display_name: string
|
|
410
|
+
[key: string]: unknown
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** Only fields being updated are present */
|
|
414
|
+
interface FilterUserUpdateData {
|
|
415
|
+
display_name?: string
|
|
416
|
+
bio?: string
|
|
417
|
+
locale?: string
|
|
418
|
+
status?: number
|
|
419
|
+
[key: string]: unknown
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
interface FilterMediaUploadData {
|
|
423
|
+
filename: string
|
|
424
|
+
mime_type: string
|
|
425
|
+
category: string
|
|
426
|
+
alt_text: string
|
|
427
|
+
title: string
|
|
428
|
+
[key: string]: unknown
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Fired when a post, page, or doc is about to be returned to the frontend.
|
|
433
|
+
* Modify `ctx.data.content` to change what the reader sees.
|
|
434
|
+
*/
|
|
435
|
+
interface FilterContentRenderData {
|
|
436
|
+
/** Raw markdown source */
|
|
437
|
+
content: string
|
|
438
|
+
/** "post" | "page" | "doc" */
|
|
439
|
+
type: string
|
|
440
|
+
id: number
|
|
441
|
+
slug: string
|
|
442
|
+
title: string
|
|
443
|
+
[key: string]: unknown
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// ---------------------------------------------------------------------------
|
|
447
|
+
// nuxtblog.http
|
|
448
|
+
// ---------------------------------------------------------------------------
|
|
449
|
+
|
|
450
|
+
interface FetchOptions {
|
|
451
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
|
|
452
|
+
/** Plain object is JSON-serialised automatically; string is sent as-is. */
|
|
453
|
+
body?: Record<string, unknown> | string
|
|
454
|
+
headers?: Record<string, string>
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
interface FetchResult<T = unknown> {
|
|
458
|
+
/** true when HTTP status is 200–299 */
|
|
459
|
+
ok: boolean
|
|
460
|
+
status: number
|
|
461
|
+
/** Auto JSON.parse'd; falls back to raw string on parse failure. */
|
|
462
|
+
body: T
|
|
463
|
+
/** Present when the request itself failed (network error, timeout, domain blocked, etc.). */
|
|
464
|
+
error?: string
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// ---------------------------------------------------------------------------
|
|
468
|
+
// nuxtblog.store
|
|
469
|
+
// ---------------------------------------------------------------------------
|
|
470
|
+
|
|
471
|
+
interface BlogStore {
|
|
472
|
+
/** Returns the stored value for `key`, or `null` if not set. */
|
|
473
|
+
get(key: string): unknown
|
|
474
|
+
/** Persists `value` under `key`. Value is JSON-serialised. */
|
|
475
|
+
set(key: string, value: unknown): void
|
|
476
|
+
/** Removes the entry for `key`. */
|
|
477
|
+
delete(key: string): void
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// ---------------------------------------------------------------------------
|
|
481
|
+
// nuxtblog.on — typed overloads
|
|
482
|
+
// ---------------------------------------------------------------------------
|
|
483
|
+
|
|
484
|
+
interface BlogOn {
|
|
485
|
+
// Post
|
|
486
|
+
(event: "post.created", handler: (payload: PostCreatedPayload) => void): void
|
|
487
|
+
(event: "post.updated", handler: (payload: PostUpdatedPayload) => void): void
|
|
488
|
+
(event: "post.published", handler: (payload: PostPublishedPayload) => void): void
|
|
489
|
+
(event: "post.deleted", handler: (payload: PostDeletedPayload) => void): void
|
|
490
|
+
(event: "post.viewed", handler: (payload: PostViewedPayload) => void): void
|
|
491
|
+
// Comment
|
|
492
|
+
(event: "comment.created", handler: (payload: CommentCreatedPayload) => void): void
|
|
493
|
+
(event: "comment.deleted", handler: (payload: CommentDeletedPayload) => void): void
|
|
494
|
+
(event: "comment.status_changed", handler: (payload: CommentStatusChangedPayload) => void): void
|
|
495
|
+
(event: "comment.approved", handler: (payload: CommentApprovedPayload) => void): void
|
|
496
|
+
// User
|
|
497
|
+
(event: "user.registered", handler: (payload: UserRegisteredPayload) => void): void
|
|
498
|
+
(event: "user.updated", handler: (payload: UserUpdatedPayload) => void): void
|
|
499
|
+
(event: "user.deleted", handler: (payload: UserDeletedPayload) => void): void
|
|
500
|
+
(event: "user.followed", handler: (payload: UserFollowedPayload) => void): void
|
|
501
|
+
(event: "user.login", handler: (payload: UserLoginPayload) => void): void
|
|
502
|
+
(event: "user.logout", handler: (payload: UserLogoutPayload) => void): void
|
|
503
|
+
// Media
|
|
504
|
+
(event: "media.uploaded", handler: (payload: MediaUploadedPayload) => void): void
|
|
505
|
+
(event: "media.deleted", handler: (payload: MediaDeletedPayload) => void): void
|
|
506
|
+
// Taxonomy / Term
|
|
507
|
+
(event: "taxonomy.created", handler: (payload: TaxonomyCreatedPayload) => void): void
|
|
508
|
+
(event: "taxonomy.deleted", handler: (payload: TaxonomyDeletedPayload) => void): void
|
|
509
|
+
(event: "term.created", handler: (payload: TermCreatedPayload) => void): void
|
|
510
|
+
(event: "term.deleted", handler: (payload: TermDeletedPayload) => void): void
|
|
511
|
+
// Reaction / Checkin
|
|
512
|
+
(event: "reaction.added", handler: (payload: ReactionPayload) => void): void
|
|
513
|
+
(event: "reaction.removed", handler: (payload: ReactionPayload) => void): void
|
|
514
|
+
(event: "checkin.done", handler: (payload: CheckinPayload) => void): void
|
|
515
|
+
// System
|
|
516
|
+
(event: "option.updated", handler: (payload: OptionUpdatedPayload) => void): void
|
|
517
|
+
(event: "plugin.installed", handler: (payload: PluginInstalledPayload) => void): void
|
|
518
|
+
(event: "plugin.uninstalled", handler: (payload: PluginUninstalledPayload) => void): void
|
|
519
|
+
/** Fallback for custom / future events */
|
|
520
|
+
(event: string, handler: (payload: unknown) => void): void
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// ---------------------------------------------------------------------------
|
|
524
|
+
// nuxtblog.filter — typed overloads
|
|
525
|
+
//
|
|
526
|
+
// Handlers receive a PluginCtx. Modify ctx.data to change the data that will
|
|
527
|
+
// be persisted. Call ctx.abort(reason) to reject the operation entirely.
|
|
528
|
+
// Calling ctx.next() is optional — the chain continues unless abort() is called.
|
|
529
|
+
// ---------------------------------------------------------------------------
|
|
530
|
+
|
|
531
|
+
interface BlogFilter {
|
|
532
|
+
(event: "post.create",
|
|
533
|
+
handler: (ctx: PluginCtx<FilterPostCreateData>) => void): void
|
|
534
|
+
(event: "post.update",
|
|
535
|
+
handler: (ctx: PluginCtx<FilterPostUpdateData>) => void): void
|
|
536
|
+
(event: "post.delete",
|
|
537
|
+
handler: (ctx: PluginCtx<FilterPostDeleteData>) => void): void
|
|
538
|
+
(event: "comment.create",
|
|
539
|
+
handler: (ctx: PluginCtx<FilterCommentCreateData>) => void): void
|
|
540
|
+
(event: "comment.delete",
|
|
541
|
+
handler: (ctx: PluginCtx<FilterCommentDeleteData>) => void): void
|
|
542
|
+
(event: "term.create",
|
|
543
|
+
handler: (ctx: PluginCtx<FilterTermCreateData>) => void): void
|
|
544
|
+
(event: "user.register",
|
|
545
|
+
handler: (ctx: PluginCtx<FilterUserRegisterData>) => void): void
|
|
546
|
+
(event: "user.update",
|
|
547
|
+
handler: (ctx: PluginCtx<FilterUserUpdateData>) => void): void
|
|
548
|
+
(event: "media.upload",
|
|
549
|
+
handler: (ctx: PluginCtx<FilterMediaUploadData>) => void): void
|
|
550
|
+
(event: "content.render",
|
|
551
|
+
handler: (ctx: PluginCtx<FilterContentRenderData>) => void): void
|
|
552
|
+
/** Fallback for custom / future filter events */
|
|
553
|
+
(event: string, handler: (ctx: PluginCtx) => void): void
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// ---------------------------------------------------------------------------
|
|
557
|
+
// Global nuxtblog object
|
|
558
|
+
// ---------------------------------------------------------------------------
|
|
559
|
+
|
|
560
|
+
declare const nuxtblog: {
|
|
561
|
+
/**
|
|
562
|
+
* Subscribe to a fire-and-forget event (async, runs after the operation completes).
|
|
563
|
+
* HTTP requests are allowed. Cannot modify or cancel the triggering operation.
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* nuxtblog.on('post.published', (data) => {
|
|
567
|
+
* nuxtblog.http.fetch('https://hooks.slack.com/...', {
|
|
568
|
+
* method: 'POST', body: { text: 'New post: ' + data.title }
|
|
569
|
+
* })
|
|
570
|
+
* })
|
|
571
|
+
*/
|
|
572
|
+
on: BlogOn
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Register a synchronous data interceptor.
|
|
576
|
+
* Runs BEFORE data is written to the database.
|
|
577
|
+
* Modify `ctx.data` to change the persisted values.
|
|
578
|
+
* Call `ctx.abort(reason)` to reject the operation entirely.
|
|
579
|
+
*
|
|
580
|
+
* ⚠️ HTTP requests (`nuxtblog.http.fetch`) are NOT allowed inside filter handlers.
|
|
581
|
+
* Use `nuxtblog.on` or a pipeline step for async side-effects.
|
|
582
|
+
*
|
|
583
|
+
* @example
|
|
584
|
+
* nuxtblog.filter('post.create', (ctx) => {
|
|
585
|
+
* if (!ctx.data.title) {
|
|
586
|
+
* ctx.abort('title is required')
|
|
587
|
+
* return
|
|
588
|
+
* }
|
|
589
|
+
* ctx.data.title = ctx.data.title.trim()
|
|
590
|
+
* })
|
|
591
|
+
*/
|
|
592
|
+
filter: BlogFilter
|
|
593
|
+
|
|
594
|
+
/** Write a message to the server log (prefixed with [plugin:<id>]). */
|
|
595
|
+
log: {
|
|
596
|
+
info(message: string): void
|
|
597
|
+
warn(message: string): void
|
|
598
|
+
error(message: string): void
|
|
599
|
+
debug(message: string): void
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Synchronous HTTP client. Available when the plugin declares `capabilities.http`.
|
|
604
|
+
*
|
|
605
|
+
* ⚠️ Blocked inside `nuxtblog.filter` handlers regardless of capability declarations.
|
|
606
|
+
* Safe to use in `nuxtblog.on` handlers and pipeline JS steps.
|
|
607
|
+
*/
|
|
608
|
+
http: {
|
|
609
|
+
/**
|
|
610
|
+
* Make a synchronous HTTP request. Default timeout: 15 seconds (overridable
|
|
611
|
+
* via `capabilities.http.timeout_ms` in the manifest).
|
|
612
|
+
* Returns immediately with the result (not a Promise).
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* const res = nuxtblog.http.fetch<{ id: number }>('https://api.example.com/notify', {
|
|
616
|
+
* method: 'POST',
|
|
617
|
+
* body: { message: 'hello' },
|
|
618
|
+
* headers: { Authorization: 'Bearer token' },
|
|
619
|
+
* })
|
|
620
|
+
* if (res.ok) nuxtblog.log.info('notified: ' + res.body.id)
|
|
621
|
+
*/
|
|
622
|
+
fetch<T = unknown>(url: string, opts?: FetchOptions): FetchResult<T>
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Per-plugin persistent key-value store backed by the blog database.
|
|
627
|
+
* Available when the plugin declares `capabilities.store`.
|
|
628
|
+
* Keys are namespaced per plugin — no cross-plugin access.
|
|
629
|
+
*/
|
|
630
|
+
store: BlogStore
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Read admin-configured plugin settings (set in Plugins → Settings gear icon).
|
|
634
|
+
* Always available. Cached for 30 seconds; changes take effect without restart.
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* const apiKey = nuxtblog.settings.get('api_key') as string
|
|
638
|
+
*/
|
|
639
|
+
settings: {
|
|
640
|
+
get(key: string): unknown
|
|
641
|
+
}
|
|
642
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuxtblog/plugin-sdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "TypeScript type definitions and base tsconfig for nuxtblog plugins",
|
|
5
|
+
"types": "index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"index.d.ts",
|
|
8
|
+
"tsconfig.json"
|
|
9
|
+
],
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/nuxtblog/plugin-sdk.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/nuxtblog/plugin-sdk",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/nuxtblog/plugin-sdk/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"nuxtblog",
|
|
20
|
+
"plugin",
|
|
21
|
+
"sdk",
|
|
22
|
+
"typescript"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"release": "npm version patch && npm publish --access public",
|
|
27
|
+
"release:minor": "npm version minor && npm publish --access public",
|
|
28
|
+
"release:major": "npm version major && npm publish --access public"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2015",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2015", "ES2016", "ES2017", "ES2018"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"noUnusedLocals": true,
|
|
13
|
+
"noUnusedParameters": true
|
|
14
|
+
},
|
|
15
|
+
"files": ["index.d.ts"]
|
|
16
|
+
}
|