@nimbalyst/extension-sdk 0.1.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/CHANGELOG.md +39 -0
- package/README.md +151 -0
- package/dist/MaterialSymbol.d.ts +2 -0
- package/dist/MaterialSymbol.d.ts.map +1 -0
- package/dist/MaterialSymbol.js +1 -0
- package/dist/clipboard.d.ts +14 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +27 -0
- package/dist/createReadOnlyHost.d.ts +45 -0
- package/dist/createReadOnlyHost.d.ts.map +1 -0
- package/dist/createReadOnlyHost.js +81 -0
- package/dist/documentPath.d.ts +6 -0
- package/dist/documentPath.d.ts.map +1 -0
- package/dist/documentPath.js +4 -0
- package/dist/externals.d.ts +23 -0
- package/dist/externals.d.ts.map +1 -0
- package/dist/externals.js +42 -0
- package/dist/externalsPlugin.d.ts +39 -0
- package/dist/externalsPlugin.d.ts.map +1 -0
- package/dist/externalsPlugin.js +251 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/tailwind.d.ts +112 -0
- package/dist/tailwind.d.ts.map +1 -0
- package/dist/tailwind.js +129 -0
- package/dist/testing.d.ts +122 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +199 -0
- package/dist/types/editor.d.ts +385 -0
- package/dist/types/editor.d.ts.map +1 -0
- package/dist/types/editor.js +15 -0
- package/dist/types/editors.d.ts +56 -0
- package/dist/types/editors.d.ts.map +1 -0
- package/dist/types/editors.js +19 -0
- package/dist/types/extension.d.ts +744 -0
- package/dist/types/extension.d.ts.map +1 -0
- package/dist/types/extension.js +4 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/panel.d.ts +575 -0
- package/dist/types/panel.d.ts.map +1 -0
- package/dist/types/panel.js +14 -0
- package/dist/types/theme.d.ts +148 -0
- package/dist/types/theme.d.ts.map +1 -0
- package/dist/types/theme.js +7 -0
- package/dist/useEditorLifecycle.d.ts +166 -0
- package/dist/useEditorLifecycle.d.ts.map +1 -0
- package/dist/useEditorLifecycle.js +327 -0
- package/dist/validate.d.ts +31 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +128 -0
- package/dist/vite.d.ts +92 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +179 -0
- package/package.json +91 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@nimbalyst/extension-sdk` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this package follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
The SDK is versioned independently of the Nimbalyst app. Each release declares its minimum compatible app version under the `nimbalyst.minAppVersion` field of `package.json`.
|
|
8
|
+
|
|
9
|
+
| SDK version | Minimum Nimbalyst app version |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| 0.1.0 | 0.58.5 |
|
|
12
|
+
|
|
13
|
+
## [Unreleased]
|
|
14
|
+
|
|
15
|
+
## [0.1.0] - Initial release
|
|
16
|
+
|
|
17
|
+
Initial public release of the Nimbalyst extension SDK.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `EditorHost` and `EditorHostProps` contract for custom editor extensions
|
|
22
|
+
- `useEditorLifecycle` hook for editor load/save/dirty/theme handling
|
|
23
|
+
- `ExtensionAITool`, `AIToolContext`, `ExtensionToolResult` types for AI tool extensions
|
|
24
|
+
- `ExtensionContext`, `ExtensionManifest`, `ExtensionContributions` for the extension manifest schema
|
|
25
|
+
- `PanelContribution`, `PanelExport`, `PanelHost` for non-file-based panels
|
|
26
|
+
- `SettingsPanelContribution`, `SettingsPanelProps` for extension settings panels
|
|
27
|
+
- `ThemeContribution` and `ThemeColors` for custom theme extensions
|
|
28
|
+
- `createExtensionConfig` Vite helper at `@nimbalyst/extension-sdk/vite`
|
|
29
|
+
- `createManifestValidationPlugin` Vite plugin to validate build output against `manifest.json`
|
|
30
|
+
- `mergeExtensionConfig` for extending the base Vite config
|
|
31
|
+
- Tailwind preset at `@nimbalyst/extension-sdk/tailwind`
|
|
32
|
+
- Testing utilities at `@nimbalyst/extension-sdk/testing`
|
|
33
|
+
- `ROLLUP_EXTERNALS`, `REQUIRED_EXTERNALS`, `EXTERNAL_PATTERNS` constants for the externals system
|
|
34
|
+
- `MaterialSymbol` re-export, `createReadOnlyHost`, `clipboard`, and document-path utilities
|
|
35
|
+
|
|
36
|
+
### Notes
|
|
37
|
+
|
|
38
|
+
- Several legacy aliases (`CustomEditorProps`, `ToolContext`, `ToolResult`, `AIToolDefinition`, `FileIconContribution`, `LexicalNodeContribution`) are exported for migration but marked `@deprecated`. They will be removed in a future major version.
|
|
39
|
+
- Requires Vite 7+ and React 18 or 19 (declared as optional peer dependencies).
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# `@nimbalyst/extension-sdk`
|
|
2
|
+
|
|
3
|
+
Build Nimbalyst extensions with a stable TypeScript contract and Vite helpers.
|
|
4
|
+
|
|
5
|
+
This package provides:
|
|
6
|
+
|
|
7
|
+
- Shared extension types such as `ExtensionContext`, `EditorHostProps`, and `ExtensionAITool`
|
|
8
|
+
- `createExtensionConfig()` for the required extension build setup
|
|
9
|
+
- `validateExtensionBundle()` for bundle and manifest validation
|
|
10
|
+
- Tailwind helpers for extension styling
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install --save-dev @nimbalyst/extension-sdk typescript vite
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If your extension renders React UI, also install:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install react react-dom
|
|
22
|
+
npm install --save-dev @vitejs/plugin-react
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Vite Setup
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import react from '@vitejs/plugin-react';
|
|
29
|
+
import { createExtensionConfig } from '@nimbalyst/extension-sdk/vite';
|
|
30
|
+
|
|
31
|
+
export default createExtensionConfig({
|
|
32
|
+
entry: './src/index.tsx',
|
|
33
|
+
plugins: [react()],
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Custom Editor Example
|
|
38
|
+
|
|
39
|
+
Use the `useEditorLifecycle` hook to handle all editor lifecycle concerns (loading, saving, echo detection, file watching, diff mode, theme):
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { useRef } from 'react';
|
|
43
|
+
import { useEditorLifecycle, type EditorHostProps } from '@nimbalyst/extension-sdk';
|
|
44
|
+
|
|
45
|
+
export function ExampleEditor({ host }: EditorHostProps) {
|
|
46
|
+
const dataRef = useRef<MyData>(defaultData);
|
|
47
|
+
|
|
48
|
+
const { isLoading, markDirty, theme } = useEditorLifecycle(host, {
|
|
49
|
+
applyContent: (data: MyData) => { dataRef.current = data; },
|
|
50
|
+
getCurrentContent: () => dataRef.current,
|
|
51
|
+
parse: (raw) => JSON.parse(raw),
|
|
52
|
+
serialize: (data) => JSON.stringify(data),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (isLoading) return <div>Loading...</div>;
|
|
56
|
+
return <MyEditorUI data={dataRef.current} onChange={markDirty} />;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const components = {
|
|
60
|
+
ExampleEditor,
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
See the [custom editors guide](packages/extension-sdk-docs/custom-editors.md) for architecture patterns and advanced options.
|
|
65
|
+
|
|
66
|
+
## Shared Editor Components
|
|
67
|
+
|
|
68
|
+
Extensions can use the host's built-in `MonacoEditor` (code) and `MarkdownEditor` (rich text) instead of bundling their own. These are provided at runtime via the externals system with zero bundle size impact. The `MarkdownEditor` is pre-configured with toolbar, image handling, and other Nimbalyst platform features.
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { MonacoEditor } from '@nimbalyst/runtime';
|
|
72
|
+
import type { EditorHostProps } from '@nimbalyst/extension-sdk';
|
|
73
|
+
|
|
74
|
+
// Use as a full file editor
|
|
75
|
+
export const MyCodeEditor = ({ host }: EditorHostProps) => {
|
|
76
|
+
return <MonacoEditor host={host} fileName={host.fileName} />;
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
For embedded read-only panels, use `createReadOnlyHost`:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
import { MonacoEditor } from '@nimbalyst/runtime';
|
|
84
|
+
import { createReadOnlyHost } from '@nimbalyst/extension-sdk';
|
|
85
|
+
|
|
86
|
+
const previewHost = createReadOnlyHost(code, {
|
|
87
|
+
fileName: 'preview.tsx',
|
|
88
|
+
theme: host.theme,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
<MonacoEditor host={previewHost} fileName="preview.tsx" />
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Type imports for props: `MonacoEditorProps`, `MonacoEditorConfig`, `MarkdownEditorProps`, `MarkdownEditorConfig` from `@nimbalyst/extension-sdk`.
|
|
95
|
+
|
|
96
|
+
## AI Tool Example
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import type {
|
|
100
|
+
ExtensionAITool,
|
|
101
|
+
ExtensionToolResult,
|
|
102
|
+
} from '@nimbalyst/extension-sdk';
|
|
103
|
+
|
|
104
|
+
export const aiTools: ExtensionAITool[] = [
|
|
105
|
+
{
|
|
106
|
+
name: 'example.describe_file',
|
|
107
|
+
description: 'Describe the active file',
|
|
108
|
+
scope: 'editor',
|
|
109
|
+
inputSchema: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
properties: {},
|
|
112
|
+
},
|
|
113
|
+
handler: async (_args, context): Promise<ExtensionToolResult> => {
|
|
114
|
+
const filePath = context.activeFilePath;
|
|
115
|
+
if (!filePath) {
|
|
116
|
+
return { success: false, error: 'No active file.' };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const content = await context.extensionContext.services.filesystem.readFile(filePath);
|
|
120
|
+
return {
|
|
121
|
+
success: true,
|
|
122
|
+
data: {
|
|
123
|
+
filePath,
|
|
124
|
+
length: content.length,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Manifest Notes
|
|
133
|
+
|
|
134
|
+
- `apiVersion` is currently optional but recommended.
|
|
135
|
+
- `contributions.aiTools` must be an array of tool-name strings, not full tool objects.
|
|
136
|
+
- `contributions.fileIcons` must be an object map such as `{ "*.csv": "table" }`.
|
|
137
|
+
|
|
138
|
+
## Docs
|
|
139
|
+
|
|
140
|
+
- Getting started: `packages/extension-sdk-docs/getting-started.md`
|
|
141
|
+
- Manifest reference: `packages/extension-sdk-docs/manifest-reference.md`
|
|
142
|
+
- API reference: `packages/extension-sdk-docs/api-reference.md`
|
|
143
|
+
- Examples: `packages/extension-sdk-docs/examples/`
|
|
144
|
+
|
|
145
|
+
## Release Checks
|
|
146
|
+
|
|
147
|
+
From the monorepo root:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm run extension-sdk:check-public
|
|
151
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MaterialSymbol.d.ts","sourceRoot":"","sources":["../src/MaterialSymbol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MaterialSymbol } from '@nimbalyst/runtime';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard utilities for Nimbalyst extensions.
|
|
3
|
+
*
|
|
4
|
+
* Routes through Electron's native clipboard via IPC when available,
|
|
5
|
+
* falling back to the standard navigator.clipboard Web API for
|
|
6
|
+
* non-Electron contexts.
|
|
7
|
+
*
|
|
8
|
+
* navigator.clipboard.writeText() can silently fail in Electron -- the
|
|
9
|
+
* promise resolves but nothing is written to the system clipboard.
|
|
10
|
+
* These helpers avoid that issue by using the IPC bridge.
|
|
11
|
+
*/
|
|
12
|
+
export declare function copyToClipboard(text: string): Promise<void>;
|
|
13
|
+
export declare function readClipboard(): Promise<string>;
|
|
14
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../src/clipboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjE;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAOrD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipboard utilities for Nimbalyst extensions.
|
|
3
|
+
*
|
|
4
|
+
* Routes through Electron's native clipboard via IPC when available,
|
|
5
|
+
* falling back to the standard navigator.clipboard Web API for
|
|
6
|
+
* non-Electron contexts.
|
|
7
|
+
*
|
|
8
|
+
* navigator.clipboard.writeText() can silently fail in Electron -- the
|
|
9
|
+
* promise resolves but nothing is written to the system clipboard.
|
|
10
|
+
* These helpers avoid that issue by using the IPC bridge.
|
|
11
|
+
*/
|
|
12
|
+
export async function copyToClipboard(text) {
|
|
13
|
+
const electronAPI = window.electronAPI;
|
|
14
|
+
if (electronAPI?.copyToClipboard) {
|
|
15
|
+
await electronAPI.copyToClipboard(text);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
await navigator.clipboard.writeText(text);
|
|
19
|
+
}
|
|
20
|
+
export async function readClipboard() {
|
|
21
|
+
const electronAPI = window.electronAPI;
|
|
22
|
+
if (electronAPI?.readClipboard) {
|
|
23
|
+
const result = await electronAPI.readClipboard();
|
|
24
|
+
return result.text ?? '';
|
|
25
|
+
}
|
|
26
|
+
return navigator.clipboard.readText();
|
|
27
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReadOnlyEditorHost factory for web share viewers.
|
|
3
|
+
*
|
|
4
|
+
* Creates a minimal EditorHost implementation that serves pre-loaded content
|
|
5
|
+
* in read-only mode. Used by the Cloudflare share viewer to render extension
|
|
6
|
+
* editors on the web without any Electron/IPC dependencies.
|
|
7
|
+
*
|
|
8
|
+
* Also useful for testing extensions in isolation.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const host = createReadOnlyHost(decryptedContent, {
|
|
13
|
+
* theme: 'dark',
|
|
14
|
+
* fileName: 'diagram.mindmap',
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Mount extension component
|
|
18
|
+
* root.render(<MindmapEditor host={host} />);
|
|
19
|
+
*
|
|
20
|
+
* // Toggle theme from viewer chrome
|
|
21
|
+
* host.setTheme('light');
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import type { EditorHost } from './types/editor.js';
|
|
25
|
+
export interface ReadOnlyHostOptions {
|
|
26
|
+
/** Current theme name (e.g., 'dark', 'light') */
|
|
27
|
+
theme: string;
|
|
28
|
+
/** File name for display */
|
|
29
|
+
fileName: string;
|
|
30
|
+
/** Optional synthetic file path (defaults to `/shared/{fileName}`) */
|
|
31
|
+
filePath?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface ReadOnlyHost extends EditorHost {
|
|
34
|
+
/** Update the theme (call from viewer chrome's theme toggle) */
|
|
35
|
+
setTheme(theme: string): void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a read-only EditorHost that serves pre-loaded content.
|
|
39
|
+
*
|
|
40
|
+
* All mutating methods (save, dirty, file change) are no-ops.
|
|
41
|
+
* The `readOnly` flag is set to `true` so extensions can check it
|
|
42
|
+
* to disable editing UI.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createReadOnlyHost(content: string, opts: ReadOnlyHostOptions): ReadOnlyHost;
|
|
45
|
+
//# sourceMappingURL=createReadOnlyHost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createReadOnlyHost.d.ts","sourceRoot":"","sources":["../src/createReadOnlyHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAiC,MAAM,mBAAmB,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IAEd,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IAEjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,GACxB,YAAY,CAyDd"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReadOnlyEditorHost factory for web share viewers.
|
|
3
|
+
*
|
|
4
|
+
* Creates a minimal EditorHost implementation that serves pre-loaded content
|
|
5
|
+
* in read-only mode. Used by the Cloudflare share viewer to render extension
|
|
6
|
+
* editors on the web without any Electron/IPC dependencies.
|
|
7
|
+
*
|
|
8
|
+
* Also useful for testing extensions in isolation.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const host = createReadOnlyHost(decryptedContent, {
|
|
13
|
+
* theme: 'dark',
|
|
14
|
+
* fileName: 'diagram.mindmap',
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Mount extension component
|
|
18
|
+
* root.render(<MindmapEditor host={host} />);
|
|
19
|
+
*
|
|
20
|
+
* // Toggle theme from viewer chrome
|
|
21
|
+
* host.setTheme('light');
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Create a read-only EditorHost that serves pre-loaded content.
|
|
26
|
+
*
|
|
27
|
+
* All mutating methods (save, dirty, file change) are no-ops.
|
|
28
|
+
* The `readOnly` flag is set to `true` so extensions can check it
|
|
29
|
+
* to disable editing UI.
|
|
30
|
+
*/
|
|
31
|
+
export function createReadOnlyHost(content, opts) {
|
|
32
|
+
let themeCallbacks = [];
|
|
33
|
+
let currentTheme = opts.theme;
|
|
34
|
+
const host = {
|
|
35
|
+
// -- File info --
|
|
36
|
+
filePath: opts.filePath ?? `/shared/${opts.fileName}`,
|
|
37
|
+
fileName: opts.fileName,
|
|
38
|
+
readOnly: true,
|
|
39
|
+
theme: currentTheme,
|
|
40
|
+
isActive: true,
|
|
41
|
+
// -- Content loading --
|
|
42
|
+
loadContent: async () => content,
|
|
43
|
+
loadBinaryContent: async () => new TextEncoder().encode(content).buffer,
|
|
44
|
+
// -- Theme --
|
|
45
|
+
onThemeChanged: (cb) => {
|
|
46
|
+
themeCallbacks.push(cb);
|
|
47
|
+
return () => {
|
|
48
|
+
themeCallbacks = themeCallbacks.filter((c) => c !== cb);
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
// -- No-ops for read-only --
|
|
52
|
+
saveContent: async () => { },
|
|
53
|
+
setDirty: () => { },
|
|
54
|
+
onSaveRequested: () => () => { },
|
|
55
|
+
onFileChanged: () => () => { },
|
|
56
|
+
openHistory: () => { },
|
|
57
|
+
registerMenuItems: (_items) => { },
|
|
58
|
+
registerEditorAPI: () => { },
|
|
59
|
+
setEditorContext: (_context) => { },
|
|
60
|
+
// -- Storage (in-memory, non-persistent) --
|
|
61
|
+
storage: {
|
|
62
|
+
get: (_key) => undefined,
|
|
63
|
+
set: async () => { },
|
|
64
|
+
delete: async () => { },
|
|
65
|
+
getGlobal: (_key) => undefined,
|
|
66
|
+
setGlobal: async () => { },
|
|
67
|
+
deleteGlobal: async () => { },
|
|
68
|
+
getSecret: async () => undefined,
|
|
69
|
+
setSecret: async () => { },
|
|
70
|
+
deleteSecret: async () => { },
|
|
71
|
+
},
|
|
72
|
+
// -- Theme toggle for viewer chrome --
|
|
73
|
+
setTheme(theme) {
|
|
74
|
+
currentTheme = theme;
|
|
75
|
+
// Update the host's own theme property
|
|
76
|
+
host.theme = theme;
|
|
77
|
+
themeCallbacks.forEach((cb) => cb(theme));
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
return host;
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentPath.d.ts","sourceRoot":"","sources":["../src/documentPath.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,eAAe,IAAI,wBAAwB,CAE1D"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Libraries that MUST be externalized by extensions.
|
|
3
|
+
*
|
|
4
|
+
* These libraries are provided by the Nimbalyst host and must not be bundled
|
|
5
|
+
* by extensions. Bundling them would cause runtime errors due to:
|
|
6
|
+
* - React: Multiple instances break hooks ("rendered more hooks than previous render")
|
|
7
|
+
* - Lexical: Extensions contribute nodes to the host's editor instance
|
|
8
|
+
*
|
|
9
|
+
* Extensions should bundle their own utility libraries (zustand, lodash, etc.)
|
|
10
|
+
* for version independence.
|
|
11
|
+
*/
|
|
12
|
+
export declare const REQUIRED_EXTERNALS: readonly ["react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime", "lexical", "@lexical/react/LexicalComposerContext", "@lexical/react/useLexicalEditable", "@lexical/react/useLexicalNodeSelection", "@lexical/utils", "@lexical/markdown"];
|
|
13
|
+
/**
|
|
14
|
+
* Regex patterns for externals that match multiple modules.
|
|
15
|
+
*/
|
|
16
|
+
export declare const EXTERNAL_PATTERNS: readonly [RegExp, RegExp];
|
|
17
|
+
/**
|
|
18
|
+
* Combined externals for rollup configuration.
|
|
19
|
+
* Use this in rollupOptions.external
|
|
20
|
+
*/
|
|
21
|
+
export declare const ROLLUP_EXTERNALS: readonly ["react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime", "lexical", "@lexical/react/LexicalComposerContext", "@lexical/react/useLexicalEditable", "@lexical/react/useLexicalNodeSelection", "@lexical/utils", "@lexical/markdown", RegExp, RegExp, "@nimbalyst/editor-context"];
|
|
22
|
+
export type RequiredExternal = (typeof REQUIRED_EXTERNALS)[number];
|
|
23
|
+
//# sourceMappingURL=externals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"externals.d.ts","sourceRoot":"","sources":["../src/externals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,6QAerB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,iBAAiB,2BAGpB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,gBAAgB,0TAInB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Libraries that MUST be externalized by extensions.
|
|
3
|
+
*
|
|
4
|
+
* These libraries are provided by the Nimbalyst host and must not be bundled
|
|
5
|
+
* by extensions. Bundling them would cause runtime errors due to:
|
|
6
|
+
* - React: Multiple instances break hooks ("rendered more hooks than previous render")
|
|
7
|
+
* - Lexical: Extensions contribute nodes to the host's editor instance
|
|
8
|
+
*
|
|
9
|
+
* Extensions should bundle their own utility libraries (zustand, lodash, etc.)
|
|
10
|
+
* for version independence.
|
|
11
|
+
*/
|
|
12
|
+
export const REQUIRED_EXTERNALS = [
|
|
13
|
+
// React core - multiple instances break hooks
|
|
14
|
+
'react',
|
|
15
|
+
'react-dom',
|
|
16
|
+
'react-dom/client',
|
|
17
|
+
'react/jsx-runtime',
|
|
18
|
+
'react/jsx-dev-runtime',
|
|
19
|
+
// Lexical - extensions contribute nodes to host's editor
|
|
20
|
+
'lexical',
|
|
21
|
+
'@lexical/react/LexicalComposerContext',
|
|
22
|
+
'@lexical/react/useLexicalEditable',
|
|
23
|
+
'@lexical/react/useLexicalNodeSelection',
|
|
24
|
+
'@lexical/utils',
|
|
25
|
+
'@lexical/markdown',
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Regex patterns for externals that match multiple modules.
|
|
29
|
+
*/
|
|
30
|
+
export const EXTERNAL_PATTERNS = [
|
|
31
|
+
/^@lexical\//,
|
|
32
|
+
/^@nimbalyst\/runtime/,
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Combined externals for rollup configuration.
|
|
36
|
+
* Use this in rollupOptions.external
|
|
37
|
+
*/
|
|
38
|
+
export const ROLLUP_EXTERNALS = [
|
|
39
|
+
...REQUIRED_EXTERNALS,
|
|
40
|
+
...EXTERNAL_PATTERNS,
|
|
41
|
+
'@nimbalyst/editor-context',
|
|
42
|
+
];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite/Rollup plugin that transforms external imports to window.__nimbalyst_extensions references.
|
|
3
|
+
*
|
|
4
|
+
* This plugin runs at BUILD TIME, transforming imports BEFORE minification.
|
|
5
|
+
* This is more robust than runtime regex transformation because:
|
|
6
|
+
* 1. Source code has predictable import syntax
|
|
7
|
+
* 2. Minification happens AFTER transformation
|
|
8
|
+
* 3. Build errors are caught early
|
|
9
|
+
*
|
|
10
|
+
* HOW IT WORKS:
|
|
11
|
+
* Instead of marking modules as "external" (which keeps bare import statements that
|
|
12
|
+
* blob URLs can't resolve), we resolve imports to virtual modules that access
|
|
13
|
+
* window.__nimbalyst_extensions at runtime.
|
|
14
|
+
*
|
|
15
|
+
* Example:
|
|
16
|
+
* import React, { useState } from 'react'
|
|
17
|
+
* ->
|
|
18
|
+
* // Generated virtual module gets bundled inline:
|
|
19
|
+
* const __mod = window.__nimbalyst_extensions["react"];
|
|
20
|
+
* export default __mod;
|
|
21
|
+
* export const useState = __mod.useState;
|
|
22
|
+
* // etc.
|
|
23
|
+
*
|
|
24
|
+
* The extension's code then imports from this virtual module, which after bundling
|
|
25
|
+
* becomes direct property accesses on window.__nimbalyst_extensions.
|
|
26
|
+
*/
|
|
27
|
+
import type { Plugin } from 'vite';
|
|
28
|
+
/**
|
|
29
|
+
* Creates a Vite plugin that transforms external imports at build time.
|
|
30
|
+
*
|
|
31
|
+
* This approach uses renderChunk to transform the final output after bundling
|
|
32
|
+
* but captures the original import information during the transform phase.
|
|
33
|
+
*
|
|
34
|
+
* The key insight: we DON'T mark these as external. Instead, we let Rollup
|
|
35
|
+
* try to resolve them, fail, and then our resolveId catches them and returns
|
|
36
|
+
* a virtual module. The virtual module's code accesses window.__nimbalyst_extensions.
|
|
37
|
+
*/
|
|
38
|
+
export declare function nimbalystExternalsPlugin(): Plugin;
|
|
39
|
+
//# sourceMappingURL=externalsPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"externalsPlugin.d.ts","sourceRoot":"","sources":["../src/externalsPlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAqDnC;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAyDjD"}
|