Editor extensions
Code that runs inside the document editor.
import { function defineMod<const TMod extends ModDefinition>(definition: TMod & ValidateModHooks<TMod>): ModThe entry point of the SDK. A mod's module default-exports one `defineMod` call and nothing else. The returned value is data. It registers nothing, starts nothing, and touches no host state. The host folds it twice. At build time it runs the module in a throwaway sandbox and reads the value to derive the serializable manifest. At runtime it folds the same value again to wire your handlers into their lanes: ext-host for commands, tools, effects, and hooks; the sandboxed renderer for views and widgets. That double fold is why the module must be pure. It is re-executed to produce the manifest, so anything at the top level, a file read, a network call, a timer, a `console` line, runs during a build with no host attached. Put behavior inside handlers: `run`, `activate`, `handle`. The `ValidateModHooks` constraint makes the call fail to typecheck when a `hook.beforeAction` targets an action that is neither a known host action nor `command:` plus one of this mod's own command ids.defineMod, function editorExtension(extension: EditorExtension): EditorExtensionDeclare a node that lives inside the document editor. This is the renderer-native lane. The module runs in the host's own renderer and shares its `lexical` and `react` instances through a live handle, and registers into the host's own editor registries. There is no RPC boundary and no webview, which is what separates it from `view` and `widget`. The `module` you point at imports from `@modular/sdk/editor` and must default-export a `defineExtension({...})` value. Anything the host can insert into a document body belongs here; use `canvasElement` for the embedded canvas instead.editorExtension } from '@modular/sdk'; export defaultdefineMod<{ readonly metadata: { readonly displayName: "Notes"; readonly description: "Editor work"; }; readonly editor: readonly [EditorExtension]; }>(definition: { readonly metadata: { readonly displayName: "Notes"; readonly description: "Editor work"; }; readonly editor: readonly [EditorExtension]; }): ModThe entry point of the SDK. A mod's module default-exports one `defineMod` call and nothing else. The returned value is data. It registers nothing, starts nothing, and touches no host state. The host folds it twice. At build time it runs the module in a throwaway sandbox and reads the value to derive the serializable manifest. At runtime it folds the same value again to wire your handlers into their lanes: ext-host for commands, tools, effects, and hooks; the sandboxed renderer for views and widgets. That double fold is why the module must be pure. It is re-executed to produce the manifest, so anything at the top level, a file read, a network call, a timer, a `console` line, runs during a build with no host attached. Put behavior inside handlers: `run`, `activate`, `handle`. The `ValidateModHooks` constraint makes the call fail to typecheck when a `hook.beforeAction` targets an action that is neither a known host action nor `command:` plus one of this mod's own command ids.defineMod({metadata: { readonly displayName: "Notes"; readonly description: "Editor work"; }metadata: { displayName: "Notes"displayName: 'Notes', description: "Editor work"description: 'Editor work' }, editor: readonly [EditorExtension]editor: [ function editorExtension(extension: EditorExtension): EditorExtensionDeclare a node that lives inside the document editor. This is the renderer-native lane. The module runs in the host's own renderer and shares its `lexical` and `react` instances through a live handle, and registers into the host's own editor registries. There is no RPC boundary and no webview, which is what separates it from `view` and `widget`. The `module` you point at imports from `@modular/sdk/editor` and must default-export a `defineExtension({...})` value. Anything the host can insert into a document body belongs here; use `canvasElement` for the embedded canvas instead.editorExtension({ EditorExtension.id: stringid: 'notes.highlight', EditorExtension.name: stringname: 'Highlight', EditorExtension.module: stringmodule: './editor/highlight', EditorExtension.exportName?: string | undefinedexportName: 'Highlight', }), ], });
Members
EditorExtension — id, name,
description, module, exportName.
module and exportName are the unusual pair. Unlike a
command, you do not hand over a function. You name a
module and the export inside it, and the host loads that code into the editor
itself rather than running it in your mod's normal context.
That indirection is what lets editor code be loaded only when an editor is open.
The editor entry point
Editor-side types come from @modular/sdk/editor — 26 exports covering the
document, blocks, and text streams. Browse them at
@modular/sdk/editor.
transcriptToEditorParts is exported from the root entry point for turning an
AI transcript into editor content.