@meith/plugin-kit 0.22.0 → 0.23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meith/plugin-kit",
3
- "version": "0.22.0",
3
+ "version": "0.23.1",
4
4
  "description": "The SDK for writing a Meith plugin: typed manifests, hooks, routes, pages and migrations.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,8 +20,8 @@
20
20
  "access": "public"
21
21
  },
22
22
  "dependencies": {
23
- "@meith/core": "^0.22.0",
24
- "@meith/theme-kit": "^0.22.0"
23
+ "@meith/core": "^0.23.1",
24
+ "@meith/theme-kit": "^0.23.1"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "react": "^19.2.0"
package/src/host.ts CHANGED
@@ -206,10 +206,10 @@ export class PluginHost {
206
206
  }
207
207
  }
208
208
 
209
- renderRegion(
209
+ async renderRegion(
210
210
  region: PluginRegion,
211
- context: PluginRegionContext,
212
- ): readonly { key: string; node: ReactNode }[] {
211
+ context: Omit<PluginRegionContext, 'runtime'>,
212
+ ): Promise<readonly { key: string; node: ReactNode }[]> {
213
213
  const entries = this.#contributions.get(region)
214
214
  if (entries === undefined) return []
215
215
 
@@ -219,7 +219,10 @@ export class PluginHost {
219
219
 
220
220
  const started = this.#now()
221
221
  try {
222
- const node = entry.contribution.render(context)
222
+ const node = await entry.contribution.render({
223
+ ...context,
224
+ runtime: this.#runtimeFor(entry.pluginKey),
225
+ })
223
226
  this.#record(entry.pluginKey, region, this.#now() - started)
224
227
  if (node !== null && node !== undefined) nodes.push({ key: entry.pluginKey, node })
225
228
  } catch (error) {
package/src/index.ts CHANGED
@@ -78,8 +78,6 @@ export {
78
78
  pluginSettingKey,
79
79
  pluginTablePrefix,
80
80
  pluginTaskId,
81
- unavailableHookRuntime,
82
- unavailablePluginRuntime,
83
81
  } from './plugin'
84
82
  export {
85
83
  createRouteRateLimiter,
@@ -111,9 +109,11 @@ export {
111
109
  type PluginUsers,
112
110
  pluginNotificationKindSpecs,
113
111
  pluginNotify,
112
+ unavailableHookRuntime,
114
113
  unavailablePluginData,
115
114
  unavailablePluginGrants,
116
115
  unavailablePluginNotify,
116
+ unavailablePluginRuntime,
117
117
  unavailablePluginUsers,
118
118
  } from './runtime'
119
119
  export {
package/src/plugin.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export type { HookRuntime, PluginRuntimeContext } from './runtime'
2
+
1
3
  import type { ReactNode } from 'react'
2
4
 
3
5
  import type { Translator } from '@meith/theme-kit'
@@ -5,18 +7,7 @@ import type { Translator } from '@meith/theme-kit'
5
7
  import { type HOOKS, type HookName, isHookName } from './hooks'
6
8
  import type { HookContext, HookValue } from './payloads'
7
9
  import { isPluginRegion, type PluginRegion, type PluginRegionContext } from './regions'
8
- import {
9
- type PluginData,
10
- type PluginGrants,
11
- type PluginNotify,
12
- type PluginUsers,
13
- unavailablePluginData,
14
- unavailablePluginGrants,
15
- unavailablePluginNotify,
16
- unavailablePluginUsers,
17
- } from './runtime'
18
-
19
- export type HookRuntime = () => Promise<PluginRuntimeContext>
10
+ import type { HookRuntime, PluginRuntimeContext } from './runtime'
20
11
 
21
12
  export type FilterHandler<K extends HookName> = (
22
13
  value: HookValue<K>,
@@ -87,7 +78,7 @@ export interface PluginAdminPage {
87
78
  export interface PluginContribution {
88
79
  readonly region: PluginRegion
89
80
  readonly priority?: number | undefined
90
- readonly render: (context: PluginRegionContext) => ReactNode
81
+ readonly render: (context: PluginRegionContext) => ReactNode | Promise<ReactNode>
91
82
  }
92
83
 
93
84
  export interface PluginViewer {
@@ -176,34 +167,6 @@ export interface PluginNavigationItem {
176
167
  readonly under?: string | undefined
177
168
  }
178
169
 
179
- export interface PluginRuntimeContext {
180
- readonly settings: Readonly<Record<string, string | number | boolean>>
181
- readonly logger: {
182
- readonly info: (message: string, detail?: Record<string, unknown>) => void
183
- readonly warn: (message: string, detail?: Record<string, unknown>) => void
184
- readonly error: (message: string, detail?: Record<string, unknown>) => void
185
- }
186
- readonly grants: PluginGrants
187
- readonly data: PluginData
188
- readonly users: PluginUsers
189
- readonly notify: PluginNotify
190
- }
191
-
192
- export function unavailablePluginRuntime(reason: string): PluginRuntimeContext {
193
- return {
194
- settings: {},
195
- logger: { info: () => {}, warn: () => {}, error: () => {} },
196
- grants: unavailablePluginGrants(reason),
197
- data: unavailablePluginData(reason),
198
- users: unavailablePluginUsers(reason),
199
- notify: unavailablePluginNotify(reason),
200
- }
201
- }
202
-
203
- export function unavailableHookRuntime(reason: string): HookRuntime {
204
- return () => Promise.resolve(unavailablePluginRuntime(reason))
205
- }
206
-
207
170
  export interface PluginNotificationKind {
208
171
  readonly key: string
209
172
  readonly title: string
package/src/regions.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { HookRuntime } from './runtime'
2
+
1
3
  export interface RegionSpec {
2
4
  readonly purpose: string
3
5
  readonly context: string
@@ -22,6 +24,12 @@ export const PLUGIN_REGIONS = {
22
24
  purpose: 'Below a post body, above its actions.',
23
25
  context: 'The viewer, the post id and the author id.',
24
26
  },
27
+ 'thread.header': {
28
+ purpose:
29
+ 'Above the first post of a thread, below its title. Runs once per thread page, ' +
30
+ 'so unlike postbit.* it can afford to read from the plugin’s own tables.',
31
+ context: 'The viewer, the thread id and the thread author’s id.',
32
+ },
25
33
  'profile.panel': {
26
34
  purpose: 'A panel on a member’s profile, below the standard fields.',
27
35
  context: 'The viewer and the profile’s member id.',
@@ -45,4 +53,5 @@ export interface PluginRegionContext {
45
53
  readonly viewer: { readonly userId: number | null; readonly isGuest: boolean }
46
54
  readonly subjectId: number | null
47
55
  readonly authorId: number | null
56
+ readonly runtime: HookRuntime
48
57
  }
package/src/runtime.ts CHANGED
@@ -246,3 +246,33 @@ export function pluginNotify(
246
246
  },
247
247
  }
248
248
  }
249
+
250
+ export interface PluginRuntimeContext {
251
+ readonly settings: Readonly<Record<string, string | number | boolean>>
252
+ readonly logger: {
253
+ readonly info: (message: string, detail?: Record<string, unknown>) => void
254
+ readonly warn: (message: string, detail?: Record<string, unknown>) => void
255
+ readonly error: (message: string, detail?: Record<string, unknown>) => void
256
+ }
257
+ readonly grants: PluginGrants
258
+ readonly data: PluginData
259
+ readonly users: PluginUsers
260
+ readonly notify: PluginNotify
261
+ }
262
+
263
+ export type HookRuntime = () => Promise<PluginRuntimeContext>
264
+
265
+ export function unavailablePluginRuntime(reason: string): PluginRuntimeContext {
266
+ return {
267
+ settings: {},
268
+ logger: { info: () => {}, warn: () => {}, error: () => {} },
269
+ grants: unavailablePluginGrants(reason),
270
+ data: unavailablePluginData(reason),
271
+ users: unavailablePluginUsers(reason),
272
+ notify: unavailablePluginNotify(reason),
273
+ }
274
+ }
275
+
276
+ export function unavailableHookRuntime(reason: string): HookRuntime {
277
+ return () => Promise.resolve(unavailablePluginRuntime(reason))
278
+ }