@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.
Files changed (57) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +151 -0
  3. package/dist/MaterialSymbol.d.ts +2 -0
  4. package/dist/MaterialSymbol.d.ts.map +1 -0
  5. package/dist/MaterialSymbol.js +1 -0
  6. package/dist/clipboard.d.ts +14 -0
  7. package/dist/clipboard.d.ts.map +1 -0
  8. package/dist/clipboard.js +27 -0
  9. package/dist/createReadOnlyHost.d.ts +45 -0
  10. package/dist/createReadOnlyHost.d.ts.map +1 -0
  11. package/dist/createReadOnlyHost.js +81 -0
  12. package/dist/documentPath.d.ts +6 -0
  13. package/dist/documentPath.d.ts.map +1 -0
  14. package/dist/documentPath.js +4 -0
  15. package/dist/externals.d.ts +23 -0
  16. package/dist/externals.d.ts.map +1 -0
  17. package/dist/externals.js +42 -0
  18. package/dist/externalsPlugin.d.ts +39 -0
  19. package/dist/externalsPlugin.d.ts.map +1 -0
  20. package/dist/externalsPlugin.js +251 -0
  21. package/dist/index.d.ts +33 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +39 -0
  24. package/dist/tailwind.d.ts +112 -0
  25. package/dist/tailwind.d.ts.map +1 -0
  26. package/dist/tailwind.js +129 -0
  27. package/dist/testing.d.ts +122 -0
  28. package/dist/testing.d.ts.map +1 -0
  29. package/dist/testing.js +199 -0
  30. package/dist/types/editor.d.ts +385 -0
  31. package/dist/types/editor.d.ts.map +1 -0
  32. package/dist/types/editor.js +15 -0
  33. package/dist/types/editors.d.ts +56 -0
  34. package/dist/types/editors.d.ts.map +1 -0
  35. package/dist/types/editors.js +19 -0
  36. package/dist/types/extension.d.ts +744 -0
  37. package/dist/types/extension.d.ts.map +1 -0
  38. package/dist/types/extension.js +4 -0
  39. package/dist/types/index.d.ts +9 -0
  40. package/dist/types/index.d.ts.map +1 -0
  41. package/dist/types/index.js +8 -0
  42. package/dist/types/panel.d.ts +575 -0
  43. package/dist/types/panel.d.ts.map +1 -0
  44. package/dist/types/panel.js +14 -0
  45. package/dist/types/theme.d.ts +148 -0
  46. package/dist/types/theme.d.ts.map +1 -0
  47. package/dist/types/theme.js +7 -0
  48. package/dist/useEditorLifecycle.d.ts +166 -0
  49. package/dist/useEditorLifecycle.d.ts.map +1 -0
  50. package/dist/useEditorLifecycle.js +327 -0
  51. package/dist/validate.d.ts +31 -0
  52. package/dist/validate.d.ts.map +1 -0
  53. package/dist/validate.js +128 -0
  54. package/dist/vite.d.ts +92 -0
  55. package/dist/vite.d.ts.map +1 -0
  56. package/dist/vite.js +179 -0
  57. package/package.json +91 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,KAAK,EAAE,OAAO,CAAC;IAEf,uDAAuD;IACvD,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,SAAa,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAkH3B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAmBpE"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Build-time validation for extension bundles.
3
+ */
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ /**
7
+ * Validates an extension bundle for common issues.
8
+ *
9
+ * Run this after building to catch configuration mistakes before runtime.
10
+ *
11
+ * @param distPath - Path to the dist directory containing the bundle
12
+ * @param bundleName - Name of the bundle file (default: 'index.js')
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const result = await validateExtensionBundle('./dist');
17
+ * if (!result.valid) {
18
+ * console.error('Build failed:', result.errors);
19
+ * process.exit(1);
20
+ * }
21
+ * ```
22
+ */
23
+ export async function validateExtensionBundle(distPath, bundleName = 'index.js') {
24
+ const errors = [];
25
+ const warnings = [];
26
+ const bundlePath = path.join(distPath, bundleName);
27
+ // Check bundle exists
28
+ if (!fs.existsSync(bundlePath)) {
29
+ errors.push(`Bundle not found at ${bundlePath}`);
30
+ return { valid: false, errors, warnings };
31
+ }
32
+ const bundle = fs.readFileSync(bundlePath, 'utf8');
33
+ // Check for dev runtime usage (jsxDEV)
34
+ // This is now just a warning since we have a shim, but it's still not ideal
35
+ if (bundle.includes('jsxDEV') && bundle.includes('jsx-dev-runtime')) {
36
+ warnings.push('Extension uses jsxDEV from react/jsx-dev-runtime. ' +
37
+ 'This works but is not recommended. Set mode: "production" in vite config ' +
38
+ 'and configure @vitejs/plugin-react with jsxRuntime: "automatic".');
39
+ }
40
+ // Check for bundled React (should be external)
41
+ if (bundle.includes('react.production.min.js') ||
42
+ bundle.includes('react.development.js') ||
43
+ bundle.includes('__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED')) {
44
+ errors.push('Extension appears to bundle React. This will cause runtime errors. ' +
45
+ 'Add "react" and "react-dom" to rollupOptions.external, or use createExtensionConfig().');
46
+ }
47
+ // Check for bundled Lexical (should be external)
48
+ if (bundle.includes('$getRoot') &&
49
+ bundle.includes('$getSelection') &&
50
+ bundle.length > 500000 // Lexical adds significant size
51
+ ) {
52
+ warnings.push('Extension may be bundling Lexical. If you use Lexical nodes, ' +
53
+ 'add "lexical" and "@lexical/*" to rollupOptions.external.');
54
+ }
55
+ // Check for unresolved process.env references
56
+ if (bundle.includes('process.env.NODE_ENV')) {
57
+ warnings.push('Bundle contains process.env.NODE_ENV references that were not replaced. ' +
58
+ 'Add define: { "process.env.NODE_ENV": JSON.stringify("production") } to vite config.');
59
+ }
60
+ // Check for CommonJS artifacts that might cause issues
61
+ if (bundle.includes('require(') && !bundle.includes('require.resolve')) {
62
+ warnings.push('Bundle contains require() calls which may not work in the browser. ' +
63
+ 'Ensure all dependencies are ESM-compatible or properly bundled.');
64
+ }
65
+ // Check manifest exists
66
+ const manifestPath = path.join(path.dirname(distPath), 'manifest.json');
67
+ if (!fs.existsSync(manifestPath)) {
68
+ warnings.push(`No manifest.json found at ${manifestPath}. ` +
69
+ 'Extensions need a manifest.json to be loaded by Nimbalyst.');
70
+ }
71
+ else {
72
+ // Validate manifest
73
+ try {
74
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
75
+ if (!manifest.id) {
76
+ errors.push('manifest.json is missing required "id" field');
77
+ }
78
+ if (!manifest.name) {
79
+ errors.push('manifest.json is missing required "name" field');
80
+ }
81
+ if (!manifest.main) {
82
+ errors.push('manifest.json is missing required "main" field');
83
+ }
84
+ else {
85
+ // Check main points to existing file
86
+ const mainPath = path.join(path.dirname(manifestPath), manifest.main);
87
+ if (!fs.existsSync(mainPath)) {
88
+ errors.push(`manifest.json "main" points to ${manifest.main} but file does not exist`);
89
+ }
90
+ }
91
+ if (manifest.styles) {
92
+ const stylesPath = path.join(path.dirname(manifestPath), manifest.styles);
93
+ if (!fs.existsSync(stylesPath)) {
94
+ warnings.push(`manifest.json "styles" points to ${manifest.styles} but file does not exist`);
95
+ }
96
+ }
97
+ }
98
+ catch (e) {
99
+ errors.push(`Failed to parse manifest.json: ${e}`);
100
+ }
101
+ }
102
+ return {
103
+ valid: errors.length === 0,
104
+ errors,
105
+ warnings,
106
+ };
107
+ }
108
+ /**
109
+ * Prints validation results to console with formatting.
110
+ */
111
+ export function printValidationResult(result) {
112
+ if (result.valid && result.warnings.length === 0) {
113
+ console.log('\x1b[32m%s\x1b[0m', ' Extension bundle validation passed');
114
+ return;
115
+ }
116
+ if (result.errors.length > 0) {
117
+ console.log('\x1b[31m%s\x1b[0m', ' Validation FAILED:');
118
+ for (const error of result.errors) {
119
+ console.log('\x1b[31m%s\x1b[0m', ` - ${error}`);
120
+ }
121
+ }
122
+ if (result.warnings.length > 0) {
123
+ console.log('\x1b[33m%s\x1b[0m', ' Warnings:');
124
+ for (const warning of result.warnings) {
125
+ console.log('\x1b[33m%s\x1b[0m', ` - ${warning}`);
126
+ }
127
+ }
128
+ }
package/dist/vite.d.ts ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Vite configuration helpers for Nimbalyst extensions.
3
+ */
4
+ import type { UserConfig, PluginOption, Plugin } from 'vite';
5
+ /**
6
+ * Creates a Vite plugin that validates the build output matches the manifest.
7
+ * This catches issues like manifest.main pointing to a file that doesn't exist
8
+ * (e.g., manifest says "dist/index.mjs" but Vite outputs "dist/index.js").
9
+ *
10
+ * The plugin runs after the build completes and fails the build if validation fails.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { createManifestValidationPlugin } from '@nimbalyst/extension-sdk/vite';
15
+ *
16
+ * export default defineConfig({
17
+ * plugins: [
18
+ * react(),
19
+ * createManifestValidationPlugin(),
20
+ * ],
21
+ * // ... rest of config
22
+ * });
23
+ * ```
24
+ */
25
+ export declare function createManifestValidationPlugin(): Plugin;
26
+ export interface ExtensionConfigOptions {
27
+ /**
28
+ * Entry point for the extension (e.g., './src/index.tsx')
29
+ */
30
+ entry: string;
31
+ /**
32
+ * Output filename (without extension). Defaults to 'index'
33
+ */
34
+ fileName?: string;
35
+ /**
36
+ * Additional externals to add beyond the required ones.
37
+ * Use this for libraries accessed via window.__nimbalyst_extensions
38
+ */
39
+ additionalExternals?: (string | RegExp)[];
40
+ /**
41
+ * Additional Vite plugins to include
42
+ */
43
+ plugins?: PluginOption[];
44
+ /**
45
+ * Whether to generate sourcemaps. Defaults to true
46
+ */
47
+ sourcemap?: boolean;
48
+ /**
49
+ * Whether to inline dynamic imports into a single file. Defaults to true.
50
+ * Required because extensions load via blob URLs which don't support relative imports.
51
+ */
52
+ inlineDynamicImports?: boolean;
53
+ }
54
+ /**
55
+ * Creates a Vite configuration for building a Nimbalyst extension.
56
+ *
57
+ * This sets up:
58
+ * - Production mode and NODE_ENV for proper React JSX transform
59
+ * - ES module output format
60
+ * - Correct externals for host-provided dependencies
61
+ * - Inlined dynamic imports (required for blob URL loading)
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * // vite.config.ts
66
+ * import { createExtensionConfig } from '@nimbalyst/extension-sdk/vite';
67
+ *
68
+ * export default createExtensionConfig({
69
+ * entry: './src/index.tsx',
70
+ * });
71
+ * ```
72
+ */
73
+ export declare function createExtensionConfig(options: ExtensionConfigOptions): UserConfig;
74
+ /**
75
+ * Merges a base extension config with custom overrides.
76
+ * Useful when you need to extend the base config.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * import { createExtensionConfig, mergeExtensionConfig } from '@nimbalyst/extension-sdk/vite';
81
+ *
82
+ * const baseConfig = createExtensionConfig({ entry: './src/index.tsx' });
83
+ *
84
+ * export default mergeExtensionConfig(baseConfig, {
85
+ * resolve: {
86
+ * alias: { '@': './src' }
87
+ * }
88
+ * });
89
+ * ```
90
+ */
91
+ export declare function mergeExtensionConfig(base: UserConfig, overrides: Partial<UserConfig>): UserConfig;
92
+ //# sourceMappingURL=vite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAK7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CA+CvD;AAED,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAE1C;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,UAAU,CAsEjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,GAC7B,UAAU,CAqBZ"}
package/dist/vite.js ADDED
@@ -0,0 +1,179 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { resolve } from 'path';
3
+ import { ROLLUP_EXTERNALS } from './externals.js';
4
+ /**
5
+ * Creates a Vite plugin that validates the build output matches the manifest.
6
+ * This catches issues like manifest.main pointing to a file that doesn't exist
7
+ * (e.g., manifest says "dist/index.mjs" but Vite outputs "dist/index.js").
8
+ *
9
+ * The plugin runs after the build completes and fails the build if validation fails.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createManifestValidationPlugin } from '@nimbalyst/extension-sdk/vite';
14
+ *
15
+ * export default defineConfig({
16
+ * plugins: [
17
+ * react(),
18
+ * createManifestValidationPlugin(),
19
+ * ],
20
+ * // ... rest of config
21
+ * });
22
+ * ```
23
+ */
24
+ export function createManifestValidationPlugin() {
25
+ let outDir = 'dist';
26
+ let rootDir = process.cwd();
27
+ return {
28
+ name: 'nimbalyst-manifest-validation',
29
+ configResolved(config) {
30
+ outDir = config.build.outDir;
31
+ rootDir = config.root;
32
+ },
33
+ closeBundle() {
34
+ const manifestPath = resolve(rootDir, 'manifest.json');
35
+ if (!existsSync(manifestPath)) {
36
+ return; // No manifest to validate against
37
+ }
38
+ try {
39
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
40
+ const errors = [];
41
+ // Validate main JS file
42
+ if (manifest.main) {
43
+ const mainPath = resolve(rootDir, manifest.main);
44
+ if (!existsSync(mainPath)) {
45
+ errors.push(`manifest.main "${manifest.main}" not found in build output`);
46
+ }
47
+ }
48
+ // Validate styles CSS file
49
+ if (manifest.styles) {
50
+ const stylesPath = resolve(rootDir, manifest.styles);
51
+ if (!existsSync(stylesPath)) {
52
+ errors.push(`manifest.styles "${manifest.styles}" not found in build output`);
53
+ }
54
+ }
55
+ if (errors.length > 0) {
56
+ console.error('\n\x1b[31m[nimbalyst-extension] Build validation failed:\x1b[0m');
57
+ errors.forEach((err) => console.error(` - ${err}`));
58
+ console.error('\nMake sure your vite.config.ts output filenames match manifest.json\n');
59
+ process.exitCode = 1;
60
+ }
61
+ }
62
+ catch {
63
+ // Ignore JSON parse errors - manifest might be invalid for other reasons
64
+ }
65
+ },
66
+ };
67
+ }
68
+ /**
69
+ * Creates a Vite configuration for building a Nimbalyst extension.
70
+ *
71
+ * This sets up:
72
+ * - Production mode and NODE_ENV for proper React JSX transform
73
+ * - ES module output format
74
+ * - Correct externals for host-provided dependencies
75
+ * - Inlined dynamic imports (required for blob URL loading)
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * // vite.config.ts
80
+ * import { createExtensionConfig } from '@nimbalyst/extension-sdk/vite';
81
+ *
82
+ * export default createExtensionConfig({
83
+ * entry: './src/index.tsx',
84
+ * });
85
+ * ```
86
+ */
87
+ export function createExtensionConfig(options) {
88
+ const { entry, fileName = 'index', additionalExternals = [], plugins = [], sourcemap = true, inlineDynamicImports = true, } = options;
89
+ // Combine required externals with any additional ones
90
+ const external = [...ROLLUP_EXTERNALS, ...additionalExternals];
91
+ return {
92
+ // Ensure production mode for proper JSX transform (jsx vs jsxDEV)
93
+ mode: 'production',
94
+ // Replace process.env.NODE_ENV at build time
95
+ // Required for libraries that use conditional exports
96
+ define: {
97
+ 'process.env.NODE_ENV': JSON.stringify('production'),
98
+ },
99
+ plugins: [
100
+ // Note: User must add @vitejs/plugin-react themselves with proper config:
101
+ // react({ jsxRuntime: 'automatic', jsxImportSource: 'react' })
102
+ ...plugins,
103
+ // Validate build output matches manifest.json
104
+ createManifestValidationPlugin(),
105
+ ],
106
+ build: {
107
+ lib: {
108
+ entry,
109
+ formats: ['es'],
110
+ fileName: () => `${fileName}.js`,
111
+ },
112
+ rollupOptions: {
113
+ external,
114
+ output: {
115
+ // Required: Extensions load via blob URLs which can't resolve relative imports
116
+ inlineDynamicImports,
117
+ // Standard globals for externals
118
+ globals: {
119
+ react: 'React',
120
+ 'react-dom': 'ReactDOM',
121
+ 'react/jsx-runtime': 'jsxRuntime',
122
+ },
123
+ // Name CSS output consistently
124
+ // Vite 7 changed assetInfo.name to assetInfo.names (array)
125
+ assetFileNames: (assetInfo) => {
126
+ if (assetInfo.names?.some((name) => name.endsWith('.css'))) {
127
+ return `${fileName}.css`;
128
+ }
129
+ return assetInfo.names?.[0] || 'asset';
130
+ },
131
+ },
132
+ },
133
+ // Output directory
134
+ outDir: 'dist',
135
+ emptyOutDir: true,
136
+ // Sourcemaps for debugging
137
+ sourcemap,
138
+ },
139
+ };
140
+ }
141
+ /**
142
+ * Merges a base extension config with custom overrides.
143
+ * Useful when you need to extend the base config.
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * import { createExtensionConfig, mergeExtensionConfig } from '@nimbalyst/extension-sdk/vite';
148
+ *
149
+ * const baseConfig = createExtensionConfig({ entry: './src/index.tsx' });
150
+ *
151
+ * export default mergeExtensionConfig(baseConfig, {
152
+ * resolve: {
153
+ * alias: { '@': './src' }
154
+ * }
155
+ * });
156
+ * ```
157
+ */
158
+ export function mergeExtensionConfig(base, overrides) {
159
+ return {
160
+ ...base,
161
+ ...overrides,
162
+ define: {
163
+ ...base.define,
164
+ ...overrides.define,
165
+ },
166
+ build: {
167
+ ...base.build,
168
+ ...overrides.build,
169
+ rollupOptions: {
170
+ ...base.build?.rollupOptions,
171
+ ...overrides.build?.rollupOptions,
172
+ },
173
+ },
174
+ resolve: {
175
+ ...base.resolve,
176
+ ...overrides.resolve,
177
+ },
178
+ };
179
+ }
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@nimbalyst/extension-sdk",
3
+ "version": "0.1.0",
4
+ "description": "SDK for building Nimbalyst extensions",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/nimbalyst/nimbalyst.git",
8
+ "directory": "packages/extension-sdk"
9
+ },
10
+ "homepage": "https://docs.nimbalyst.com/extensions",
11
+ "bugs": {
12
+ "url": "https://github.com/nimbalyst/nimbalyst/issues"
13
+ },
14
+ "type": "module",
15
+ "sideEffects": false,
16
+ "nimbalyst": {
17
+ "minAppVersion": "0.58.5"
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "main": "dist/index.js",
23
+ "types": "dist/index.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js"
28
+ },
29
+ "./vite": {
30
+ "types": "./dist/vite.d.ts",
31
+ "import": "./dist/vite.js"
32
+ },
33
+ "./tailwind": {
34
+ "types": "./dist/tailwind.d.ts",
35
+ "import": "./dist/tailwind.js"
36
+ },
37
+ "./testing": {
38
+ "types": "./dist/testing.d.ts",
39
+ "import": "./dist/testing.js"
40
+ }
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "README.md",
45
+ "CHANGELOG.md"
46
+ ],
47
+ "scripts": {
48
+ "build": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" && tsc",
49
+ "dev": "tsc --watch",
50
+ "typecheck": "tsc --noEmit",
51
+ "prepublishOnly": "npm run build"
52
+ },
53
+ "dependencies": {},
54
+ "peerDependencies": {
55
+ "react": "^18.2.0 || ^19.0.0",
56
+ "vite": "^7.1.12",
57
+ "@vitejs/plugin-react": "^5.1.2",
58
+ "tailwindcss": "^3.4.0"
59
+ },
60
+ "peerDependenciesMeta": {
61
+ "react": {
62
+ "optional": true
63
+ },
64
+ "vite": {
65
+ "optional": true
66
+ },
67
+ "@vitejs/plugin-react": {
68
+ "optional": true
69
+ },
70
+ "tailwindcss": {
71
+ "optional": true
72
+ }
73
+ },
74
+ "devDependencies": {
75
+ "@types/node": "^20.0.0",
76
+ "@types/react": "^18.2.0",
77
+ "react": "^18.2.0",
78
+ "typescript": "^5.0.0",
79
+ "vite": "^7.1.12",
80
+ "@vitejs/plugin-react": "^5.1.2"
81
+ },
82
+ "keywords": [
83
+ "nimbalyst",
84
+ "extension",
85
+ "sdk",
86
+ "plugin",
87
+ "custom-editor",
88
+ "ai-tools"
89
+ ],
90
+ "license": "MIT"
91
+ }