@abraca/plugin 2.3.0
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/abracadabra-plugin.cjs +557 -0
- package/dist/abracadabra-plugin.cjs.map +1 -0
- package/dist/abracadabra-plugin.esm.js +549 -0
- package/dist/abracadabra-plugin.esm.js.map +1 -0
- package/dist/index.d.ts +642 -0
- package/package.json +32 -0
- package/src/host.ts +221 -0
- package/src/index.ts +67 -0
- package/src/manifest.ts +173 -0
- package/src/registry.ts +287 -0
- package/src/sandbox.ts +381 -0
- package/src/source-spec.ts +81 -0
- package/src/types.ts +353 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin source specification — the user-typed shorthand that resolves to a
|
|
3
|
+
* loadable URL.
|
|
4
|
+
*
|
|
5
|
+
* Today the registry server (Phase C) hosts artifacts at canonical URLs.
|
|
6
|
+
* Until then, both `cou-shell` and `@abraca/nuxt` accept three forms:
|
|
7
|
+
*
|
|
8
|
+
* - `npm:<package>[@version]` → jsDelivr npm CDN
|
|
9
|
+
* - `github:<user>/<repo>[@ref]` → jsDelivr GitHub CDN
|
|
10
|
+
* - any other string → returned as-is (must be `https://` or `http://localhost`)
|
|
11
|
+
*
|
|
12
|
+
* Once Phase C ships we add:
|
|
13
|
+
*
|
|
14
|
+
* - `abra:<plugin-id>[@version]` → the official registry
|
|
15
|
+
*
|
|
16
|
+
* The output URL points at the plugin's bundle entry. Convention is
|
|
17
|
+
* `<root>/dist/plugin.js`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** A locally-installed external plugin record (persisted to host storage). */
|
|
21
|
+
export interface ExternalPluginEntry {
|
|
22
|
+
/** Resolved fetch URL — the output of `normalizePluginUrl`. */
|
|
23
|
+
url: string;
|
|
24
|
+
/** Plugin `name` from the loaded bundle's manifest / default export. */
|
|
25
|
+
name: string;
|
|
26
|
+
label?: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
/** Most recent load error, if any. Cleared on next successful load. */
|
|
31
|
+
error?: string;
|
|
32
|
+
installedAt: number;
|
|
33
|
+
/**
|
|
34
|
+
* Integrity hash from the plugin's manifest, if known. Verified on every
|
|
35
|
+
* load — a silent change indicates supply-chain tampering and the host
|
|
36
|
+
* should refuse to instantiate the plugin.
|
|
37
|
+
*/
|
|
38
|
+
integrity?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a user-typed plugin spec to a fetchable URL.
|
|
43
|
+
*
|
|
44
|
+
* - `npm:foo@1.2.3` → `https://cdn.jsdelivr.net/npm/foo@1.2.3/dist/plugin.js`
|
|
45
|
+
* - `github:org/repo@main` → `https://cdn.jsdelivr.net/gh/org/repo@main/dist/plugin.js`
|
|
46
|
+
* - anything else → returned trimmed, unchanged
|
|
47
|
+
*/
|
|
48
|
+
export function normalizePluginUrl(input: string): string {
|
|
49
|
+
const trimmed = input.trim();
|
|
50
|
+
if (trimmed.startsWith("npm:")) {
|
|
51
|
+
const pkg = trimmed.slice(4);
|
|
52
|
+
return `https://cdn.jsdelivr.net/npm/${pkg}/dist/plugin.js`;
|
|
53
|
+
}
|
|
54
|
+
if (trimmed.startsWith("github:")) {
|
|
55
|
+
const repo = trimmed.slice(7);
|
|
56
|
+
return `https://cdn.jsdelivr.net/gh/${repo}/dist/plugin.js`;
|
|
57
|
+
}
|
|
58
|
+
return trimmed;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Reject any URL that isn't HTTPS or localhost over HTTP. Hosts should call
|
|
63
|
+
* this before importing — `normalizePluginUrl` does not enforce the policy
|
|
64
|
+
* (npm:/github: shorthand always produces HTTPS, so callers only need this
|
|
65
|
+
* for raw third-party URLs).
|
|
66
|
+
*/
|
|
67
|
+
export function isSafePluginUrl(url: string): boolean {
|
|
68
|
+
try {
|
|
69
|
+
const u = new URL(url);
|
|
70
|
+
if (u.protocol === "https:") return true;
|
|
71
|
+
if (
|
|
72
|
+
u.protocol === "http:" &&
|
|
73
|
+
(u.hostname === "localhost" || u.hostname === "127.0.0.1")
|
|
74
|
+
) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
} catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared plugin contract for cou-shell and `@abraca/nuxt`.
|
|
3
|
+
*
|
|
4
|
+
* `AbraPlugin` is the universal interface every plugin satisfies. App-specific
|
|
5
|
+
* supersets (`CouPlugin`, `AbracadabraPlugin`) extend or intersect this with
|
|
6
|
+
* tightened contribution shapes — TipTap toolbar items, Nuxt UI dropdown
|
|
7
|
+
* items, page-type renderers, file importers, etc.
|
|
8
|
+
*
|
|
9
|
+
* Zero peer-dep types. `Y.Doc`, `@tiptap/core`'s `Extension`, and Vue's
|
|
10
|
+
* `Component` are all referenced via local structural markers (`AbraYDoc`,
|
|
11
|
+
* `AbraTiptapExtension`, `unknown`) so this package compiles in isolation
|
|
12
|
+
* and can be consumed by hosts on any TipTap / yjs / Vue version without
|
|
13
|
+
* dragging duplicate-type fights along.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Structural marker for `yjs`'s `Y.Doc`. Defined locally — and intentionally
|
|
18
|
+
* permissive — so the plugin contract doesn't pin a specific yjs version. Any
|
|
19
|
+
* `Y.Doc` from any minor yjs version (13.6.29, 13.6.30, …) is structurally
|
|
20
|
+
* compatible. Consumers cast back to their own `Y.Doc` as needed.
|
|
21
|
+
*/
|
|
22
|
+
export interface AbraYDoc {
|
|
23
|
+
readonly clientID?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Structural marker for `@tiptap/core`'s `Extension`. Defined locally — and
|
|
28
|
+
* intentionally permissive — so the plugin contract doesn't pin a specific
|
|
29
|
+
* TipTap version. Any `Extension` from any minor TipTap version (3.22.5,
|
|
30
|
+
* 3.23.2, …) is structurally compatible. Consumers cast back to their own
|
|
31
|
+
* `Extension` as needed.
|
|
32
|
+
*/
|
|
33
|
+
export interface AbraTiptapExtension {
|
|
34
|
+
readonly name?: string;
|
|
35
|
+
readonly type?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── Plugin definition ──────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The universal plugin shape. Every plugin in the Abracadabra ecosystem
|
|
42
|
+
* (built-in or third-party, in cou-shell or any `@abraca/nuxt` consumer)
|
|
43
|
+
* satisfies this interface.
|
|
44
|
+
*
|
|
45
|
+
* Contribution fields use widened shapes (`unknown`, `Record<string, unknown>`)
|
|
46
|
+
* where the concrete type is consumer-defined. App-level plugin aliases
|
|
47
|
+
* (e.g. `CouPlugin`, `AbracadabraPlugin`) narrow them.
|
|
48
|
+
*/
|
|
49
|
+
export interface AbraPlugin {
|
|
50
|
+
/** Unique slug. Must be stable across versions, e.g. `core`, `kanban`, `my-plugin`. */
|
|
51
|
+
name: string;
|
|
52
|
+
/** Human-readable label shown in plugin browsers. Falls back to `name`. */
|
|
53
|
+
label?: string;
|
|
54
|
+
/** Plugin version. Should follow semver. */
|
|
55
|
+
version?: string;
|
|
56
|
+
/** One-line plugin description shown in browsers and scorecards. */
|
|
57
|
+
description?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Whether a built-in plugin is enabled by default. `true` if omitted.
|
|
60
|
+
* Only consulted for plugins that ship as built-ins; external plugins
|
|
61
|
+
* are opt-in regardless.
|
|
62
|
+
*/
|
|
63
|
+
defaultEnabled?: boolean;
|
|
64
|
+
|
|
65
|
+
// ── Editor contributions ────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
/** TipTap extensions (nodes, marks, extensions) contributed by this plugin. */
|
|
68
|
+
extensions?: () => AbraTiptapExtension[];
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Optional promise that resolves when this plugin's extensions are fully
|
|
72
|
+
* loaded. Used by `PluginRegistry.waitForExtensions()` so the editor
|
|
73
|
+
* doesn't initialise before async extension bundles are ready.
|
|
74
|
+
*/
|
|
75
|
+
extensionsReady?: Promise<void>;
|
|
76
|
+
|
|
77
|
+
/** Page-type renderers keyed by type slug. Concrete shape is consumer-defined. */
|
|
78
|
+
pageTypes?: Record<string, unknown>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Custom editor handlers (e.g. `table`, `fileUpload`). Each entry merges
|
|
82
|
+
* into the host's handler map. Handler signatures are consumer-defined —
|
|
83
|
+
* cou-shell types them as `EditorHandler` from `@nuxt/ui` (which uses
|
|
84
|
+
* specific arg counts that wouldn't match `(...args: any[]) => any`), the
|
|
85
|
+
* module uses a different shape; the shared contract just promises a
|
|
86
|
+
* record of any values.
|
|
87
|
+
*/
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
customHandlers?: () => Record<string, any>;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Editor toolbar / menu / slash-command / drag-handle contributions.
|
|
93
|
+
*
|
|
94
|
+
* The context shape and item-group shape are both consumer-defined. Method
|
|
95
|
+
* shorthand syntax is used deliberately — interface-method positions are
|
|
96
|
+
* bivariant in TypeScript, so app-specific aliases (`AbracadabraPlugin`,
|
|
97
|
+
* `CouPlugin`) can narrow `ctx` to their own tightened context types
|
|
98
|
+
* without `Omit`-and-rewrite gymnastics.
|
|
99
|
+
*/
|
|
100
|
+
toolbarItems?(ctx: EditorPluginCtx): readonly (readonly unknown[])[];
|
|
101
|
+
|
|
102
|
+
bubbleMenuItems?(ctx: EditorPluginCtx): readonly (readonly unknown[])[];
|
|
103
|
+
|
|
104
|
+
suggestionItems?(ctx: EditorPluginCtx): readonly (readonly unknown[])[];
|
|
105
|
+
|
|
106
|
+
dragHandleItems?(ctx: DragHandlePluginCtx): readonly (readonly unknown[])[];
|
|
107
|
+
|
|
108
|
+
/** Mention (@) providers contributing items to the mention popup. */
|
|
109
|
+
mentionProviders?: AbraMentionProvider[];
|
|
110
|
+
|
|
111
|
+
/** Awareness field declarations — keys this plugin reads/writes on awareness. */
|
|
112
|
+
awarenessContributions?: AbraAwarenessContribution[];
|
|
113
|
+
|
|
114
|
+
/** Global command-palette (⌘K) items. */
|
|
115
|
+
commandPaletteItems?(
|
|
116
|
+
ctx: CommandPaletteCtx,
|
|
117
|
+
): readonly AbraCommandItem[] | Promise<readonly AbraCommandItem[]>;
|
|
118
|
+
|
|
119
|
+
/** Extra tabs rendered in the child-document slideover panel. */
|
|
120
|
+
nodePanelSlots?: AbraNodePanelSlot[];
|
|
121
|
+
|
|
122
|
+
/** Settings panel contributed to the global settings view. */
|
|
123
|
+
settingsPanel?: AbraSettingsPanel;
|
|
124
|
+
|
|
125
|
+
/** Global keyboard shortcuts (document-level, not inside TipTap scope). */
|
|
126
|
+
keyboardShortcuts?: AbraKeyboardShortcut[];
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Client-side setup hook — called once after the client + provider are
|
|
130
|
+
* ready. May return a teardown function called on app unmount.
|
|
131
|
+
*/
|
|
132
|
+
clientSetup?(
|
|
133
|
+
ctx: ClientPluginCtx,
|
|
134
|
+
):
|
|
135
|
+
| undefined
|
|
136
|
+
| void
|
|
137
|
+
| (() => void)
|
|
138
|
+
| Promise<undefined | void | (() => void)>;
|
|
139
|
+
|
|
140
|
+
// ── Server-side contributions ───────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
/** TipTap extensions safe for server-side Y.Doc → HTML rendering (no Vue NodeViews). */
|
|
143
|
+
serverExtensions?: () => AbraTiptapExtension[];
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Custom cache renderer for non-doc page types. Receives the Y.Doc and
|
|
147
|
+
* returns serialisable data for the host's cache. Method shorthand —
|
|
148
|
+
* bivariant, so consumer plugins can narrow the `ydoc` parameter to a
|
|
149
|
+
* real `Y.Doc` from their own yjs version.
|
|
150
|
+
*/
|
|
151
|
+
serverCacheRenderer?(docId: string, ydoc: AbraYDoc): unknown;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Server-side background runners (Nitro context, service-role identity).
|
|
155
|
+
*
|
|
156
|
+
* Typed as `unknown[]` in the shared contract because each host wraps
|
|
157
|
+
* the runner ctx with its own `AbracadabraClient` / `AbracadabraProvider`
|
|
158
|
+
* / `DocCacheAPI` / etc. — a structural override here would force every
|
|
159
|
+
* consumer to either match the shared base structure exactly or fight
|
|
160
|
+
* input-contravariance. Consumers narrow this to their own
|
|
161
|
+
* `ServerRunnerDefinition[]` in their `CouPlugin` / `AbracadabraPlugin`
|
|
162
|
+
* aliases.
|
|
163
|
+
*/
|
|
164
|
+
serverRunners?: readonly unknown[];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ── Context objects ────────────────────────────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Context passed to editor-scoped plugin hooks.
|
|
171
|
+
*
|
|
172
|
+
* `editor` is the TipTap editor wrapped in whatever ref-like the host uses
|
|
173
|
+
* (`ShallowRef<Editor | null>` in Vue 3 hosts). Typed as a structural ref to
|
|
174
|
+
* avoid pulling `vue` into the type closure of plugin consumers that don't
|
|
175
|
+
* use Vue.
|
|
176
|
+
*/
|
|
177
|
+
export interface EditorPluginCtx<TEditor = unknown> {
|
|
178
|
+
editor: EditorRefLike<TEditor>;
|
|
179
|
+
docId: string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Context passed to drag-handle plugin hooks. Carries the currently-selected
|
|
184
|
+
* node plus its document position.
|
|
185
|
+
*/
|
|
186
|
+
export interface DragHandlePluginCtx<TEditor = unknown, TNode = unknown>
|
|
187
|
+
extends EditorPluginCtx<TEditor> {
|
|
188
|
+
selectedNode: RefLike<
|
|
189
|
+
{ node: TNode | null; pos: number } | undefined
|
|
190
|
+
>;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Context passed to `clientSetup`. `abracadabra` is the host's full reactive
|
|
195
|
+
* state — typed as `unknown` here; app-specific plugin aliases tighten this
|
|
196
|
+
* to `AbracadabraState` / `ReturnType<typeof useAbracadabra>` / similar.
|
|
197
|
+
*/
|
|
198
|
+
export interface ClientPluginCtx<TState = unknown> {
|
|
199
|
+
abracadabra: TState;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Context passed to command-palette plugin hooks. */
|
|
203
|
+
export interface CommandPaletteCtx<TState = unknown, TTree = unknown> {
|
|
204
|
+
docId: string | null;
|
|
205
|
+
/** `useRouter()`'s return value. Typed as `unknown` to avoid a `vue-router` peer dep. */
|
|
206
|
+
router: unknown;
|
|
207
|
+
abracadabra: TState;
|
|
208
|
+
tree: TTree | null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Context passed to mention provider hooks. */
|
|
212
|
+
export interface MentionPluginCtx {
|
|
213
|
+
docId: string;
|
|
214
|
+
connectedUsers: readonly CollaborationUser[];
|
|
215
|
+
rootDoc: AbraYDoc;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ── Ref-like primitives ────────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Minimal shape of a Vue `Ref`/`ShallowRef`/Solid signal. Defined locally so
|
|
222
|
+
* the plugin contract doesn't depend on a specific reactivity library.
|
|
223
|
+
*/
|
|
224
|
+
export interface RefLike<T> {
|
|
225
|
+
value: T;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** A read-mostly ref for the TipTap editor instance. */
|
|
229
|
+
export type EditorRefLike<TEditor = unknown> = RefLike<TEditor | null>;
|
|
230
|
+
|
|
231
|
+
// ── Contribution types ────────────────────────────────────────────────────────
|
|
232
|
+
|
|
233
|
+
export interface AbraMentionProvider {
|
|
234
|
+
/** Group label shown in the suggestion popup. */
|
|
235
|
+
label: string;
|
|
236
|
+
/**
|
|
237
|
+
* Method shorthand (not arrow property) — TS treats this position as
|
|
238
|
+
* bivariant, so consumer plugins can narrow `ctx` to their own tightened
|
|
239
|
+
* mention-context type without contravariance fights.
|
|
240
|
+
*/
|
|
241
|
+
getItems(
|
|
242
|
+
query: string,
|
|
243
|
+
ctx: MentionPluginCtx,
|
|
244
|
+
): readonly AbraMentionItem[] | Promise<readonly AbraMentionItem[]>;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface AbraMentionItem {
|
|
248
|
+
id: string;
|
|
249
|
+
label: string;
|
|
250
|
+
avatar?: string;
|
|
251
|
+
color?: string;
|
|
252
|
+
attrs?: Record<string, unknown>;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface AbraAwarenessContribution {
|
|
256
|
+
/** Namespaced keys this plugin writes, e.g. `['cursor', 'presence:kanban']`. */
|
|
257
|
+
keys: readonly string[];
|
|
258
|
+
/**
|
|
259
|
+
* Optional Vue component rendered as a presence overlay. Typed as
|
|
260
|
+
* `unknown` so the plugin contract stays Vue-free at the type level.
|
|
261
|
+
* Concrete consumers cast to `Component` / `DefineComponent` as needed.
|
|
262
|
+
*/
|
|
263
|
+
cursorComponent?: unknown;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export interface AbraCommandItem {
|
|
267
|
+
id: string;
|
|
268
|
+
label: string;
|
|
269
|
+
description?: string;
|
|
270
|
+
icon?: string;
|
|
271
|
+
group?: string;
|
|
272
|
+
shortcut?: string;
|
|
273
|
+
/** Method shorthand — bivariant, so consumer types can narrow `ctx`. */
|
|
274
|
+
when?(ctx: CommandPaletteCtx): boolean;
|
|
275
|
+
/** Method shorthand — bivariant, so consumer types can narrow `ctx`. */
|
|
276
|
+
handler(ctx: CommandPaletteCtx): void | Promise<void>;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export interface AbraNodePanelSlot {
|
|
280
|
+
id: string;
|
|
281
|
+
label: string;
|
|
282
|
+
icon: string;
|
|
283
|
+
/** Method shorthand — bivariant, so consumer types can narrow `ctx`. */
|
|
284
|
+
when(ctx: NodePanelCtx): boolean;
|
|
285
|
+
component: unknown;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export interface NodePanelCtx {
|
|
289
|
+
childId: string;
|
|
290
|
+
childDoc: AbraYDoc | null;
|
|
291
|
+
parentDocId: string;
|
|
292
|
+
parentType: string | undefined;
|
|
293
|
+
meta: Record<string, unknown>;
|
|
294
|
+
tree: unknown;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface AbraSettingsPanel {
|
|
298
|
+
label: string;
|
|
299
|
+
icon: string;
|
|
300
|
+
component: unknown;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export interface AbraKeyboardShortcut {
|
|
304
|
+
/** Key spec, e.g. `'Meta+Shift+K'`, `'Control+Alt+P'`. */
|
|
305
|
+
key: string;
|
|
306
|
+
description: string;
|
|
307
|
+
handler: () => void | Promise<void>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ── Collaboration / presence ──────────────────────────────────────────────────
|
|
311
|
+
|
|
312
|
+
export interface CollaborationUser {
|
|
313
|
+
name: string;
|
|
314
|
+
color: string;
|
|
315
|
+
publicKey?: string;
|
|
316
|
+
docId?: string;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ── Server runners ────────────────────────────────────────────────────────────
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Cleanup function returned by a runner's `start()`. Called on graceful
|
|
323
|
+
* server shutdown.
|
|
324
|
+
*/
|
|
325
|
+
export type RunnerCleanup =
|
|
326
|
+
| (() => void | Promise<void>)
|
|
327
|
+
| undefined
|
|
328
|
+
| void;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* A named background task that runs inside the host's server process
|
|
332
|
+
* (Nitro, in `@abraca/nuxt`'s case).
|
|
333
|
+
*
|
|
334
|
+
* The runner context is parameterised so each host can extend it with its
|
|
335
|
+
* own client/provider/storage shapes without the plugin contract dragging
|
|
336
|
+
* `@abraca/dabra` along.
|
|
337
|
+
*/
|
|
338
|
+
export interface ServerRunnerDefinition<TCtx = ServerRunnerContextBase> {
|
|
339
|
+
name: string;
|
|
340
|
+
/** Method shorthand — bivariant, so consumer types can narrow `ctx`. */
|
|
341
|
+
start(ctx: TCtx): Promise<RunnerCleanup> | RunnerCleanup;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Minimum context every server runner receives. Hosts extend this with
|
|
346
|
+
* `client`, `wsp`, `rootProvider`, etc.
|
|
347
|
+
*/
|
|
348
|
+
export interface ServerRunnerContextBase {
|
|
349
|
+
/** Root Y.Doc (the world / hub doc, or the space root doc for space-scoped runners). */
|
|
350
|
+
rootDoc: AbraYDoc;
|
|
351
|
+
/** Space ID if this runner is scoped to a space; `null` for hub-scoped runners. */
|
|
352
|
+
spaceId?: string | null;
|
|
353
|
+
}
|