From b91be496c3c36a8bfe61b57943ea890554e0df3a Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Thu, 3 Apr 2025 13:10:00 +0300 Subject: [PATCH] feat: Add example `@n8n/n8n-extension-insights` extension package (#14360) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Iván Ovejero --- packages/@n8n/extension-sdk/package.json | 8 +++ .../@n8n/extension-sdk/src/backend/define.ts | 6 +- .../@n8n/extension-sdk/src/backend/types.ts | 14 +++-- .../@n8n/extension-sdk/src/frontend/define.ts | 6 +- .../@n8n/extension-sdk/src/frontend/types.ts | 11 ++-- packages/@n8n/extension-sdk/tsconfig.json | 1 - packages/@n8n/extension-sdk/tsup.config.ts | 13 ++++- packages/extensions/insights/.gitignore | 24 ++++++++ packages/extensions/insights/LICENSE | 1 + packages/extensions/insights/README.md | 1 + .../extensions/insights/n8n.manifest.json | 23 ++++++++ packages/extensions/insights/package.json | 56 +++++++++++++++++++ .../extensions/insights/src/backend/index.ts | 7 +++ .../src/frontend/InsightsDashboard.vue | 6 ++ .../extensions/insights/src/frontend/index.ts | 9 +++ packages/extensions/insights/src/shims.d.ts | 1 + .../extensions/insights/tsconfig.backend.json | 9 +++ .../insights/tsconfig.frontend.json | 7 +++ packages/extensions/insights/tsconfig.json | 8 +++ .../extensions/insights/tsconfig.vite.json | 20 +++++++ packages/extensions/insights/tsup.config.ts | 15 +++++ packages/extensions/insights/vite.config.ts | 42 ++++++++++++++ pnpm-lock.yaml | 33 ++++++++++- pnpm-workspace.yaml | 1 + 24 files changed, 300 insertions(+), 22 deletions(-) create mode 100644 packages/extensions/insights/.gitignore create mode 100644 packages/extensions/insights/LICENSE create mode 100644 packages/extensions/insights/README.md create mode 100644 packages/extensions/insights/n8n.manifest.json create mode 100644 packages/extensions/insights/package.json create mode 100644 packages/extensions/insights/src/backend/index.ts create mode 100644 packages/extensions/insights/src/frontend/InsightsDashboard.vue create mode 100644 packages/extensions/insights/src/frontend/index.ts create mode 100644 packages/extensions/insights/src/shims.d.ts create mode 100644 packages/extensions/insights/tsconfig.backend.json create mode 100644 packages/extensions/insights/tsconfig.frontend.json create mode 100644 packages/extensions/insights/tsconfig.json create mode 100644 packages/extensions/insights/tsconfig.vite.json create mode 100644 packages/extensions/insights/tsup.config.ts create mode 100644 packages/extensions/insights/vite.config.ts diff --git a/packages/@n8n/extension-sdk/package.json b/packages/@n8n/extension-sdk/package.json index cba09a6a22..529b9b0f61 100644 --- a/packages/@n8n/extension-sdk/package.json +++ b/packages/@n8n/extension-sdk/package.json @@ -7,7 +7,15 @@ "LICENSE", "README.md" ], + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, "./backend": { "types": "./dist/backend/index.d.ts", "import": "./dist/backend/index.js", diff --git a/packages/@n8n/extension-sdk/src/backend/define.ts b/packages/@n8n/extension-sdk/src/backend/define.ts index e55d3605fe..06b5edf87e 100644 --- a/packages/@n8n/extension-sdk/src/backend/define.ts +++ b/packages/@n8n/extension-sdk/src/backend/define.ts @@ -1,5 +1,5 @@ -import type { BackendModule } from './types.ts'; +import type { BackendExtension } from './types.ts'; -export function defineBackendModule(module: BackendModule): BackendModule { - return module; +export function defineBackendExtension(extension: BackendExtension): BackendExtension { + return extension; } diff --git a/packages/@n8n/extension-sdk/src/backend/types.ts b/packages/@n8n/extension-sdk/src/backend/types.ts index 48eceeb7db..fde3200d14 100644 --- a/packages/@n8n/extension-sdk/src/backend/types.ts +++ b/packages/@n8n/extension-sdk/src/backend/types.ts @@ -1,7 +1,9 @@ -export type BackendModuleContext = {}; - -export type BackendModuleSetupFn = (context: BackendModule) => void; - -export type BackendModule = { - setup: BackendModuleSetupFn; +export type BackendExtensionContext = { + example?: string; +}; + +export type BackendExtensionSetupFn = (context: BackendExtension) => void; + +export type BackendExtension = { + setup: BackendExtensionSetupFn; }; diff --git a/packages/@n8n/extension-sdk/src/frontend/define.ts b/packages/@n8n/extension-sdk/src/frontend/define.ts index c88169560f..0efd83f499 100644 --- a/packages/@n8n/extension-sdk/src/frontend/define.ts +++ b/packages/@n8n/extension-sdk/src/frontend/define.ts @@ -1,5 +1,5 @@ -import type { FrontendModule } from './types.ts'; +import type { FrontendExtension } from './types.ts'; -export function defineFrontendModule(module: FrontendModule): FrontendModule { - return module; +export function defineFrontendExtension(extension: FrontendExtension): FrontendExtension { + return extension; } diff --git a/packages/@n8n/extension-sdk/src/frontend/types.ts b/packages/@n8n/extension-sdk/src/frontend/types.ts index d5e8f7a32b..6145995624 100644 --- a/packages/@n8n/extension-sdk/src/frontend/types.ts +++ b/packages/@n8n/extension-sdk/src/frontend/types.ts @@ -1,13 +1,14 @@ import type { RouteRecordRaw } from 'vue-router'; -import type { App } from 'vue'; +import type { App, Component } from 'vue'; -export type FrontendModuleContext = { +export type FrontendExtensionContext = { app: App; defineRoutes: (routes: RouteRecordRaw[]) => void; + registerComponent: (name: string, component: Component) => void; }; -export type FrontendModuleSetupFn = (context: FrontendModuleContext) => void; +export type FrontendExtensionSetupFn = (context: FrontendExtensionContext) => void; -export type FrontendModule = { - setup: FrontendModuleSetupFn; +export type FrontendExtension = { + setup: FrontendExtensionSetupFn; }; diff --git a/packages/@n8n/extension-sdk/tsconfig.json b/packages/@n8n/extension-sdk/tsconfig.json index b1d8a661a9..6e87353673 100644 --- a/packages/@n8n/extension-sdk/tsconfig.json +++ b/packages/@n8n/extension-sdk/tsconfig.json @@ -1,4 +1,3 @@ { - "files": ["./src/index.ts"], "references": [{ "path": "./tsconfig.backend.json" }, { "path": "./tsconfig.frontend.json" }] } diff --git a/packages/@n8n/extension-sdk/tsup.config.ts b/packages/@n8n/extension-sdk/tsup.config.ts index 7c0d8a58b1..d8b81c3311 100644 --- a/packages/@n8n/extension-sdk/tsup.config.ts +++ b/packages/@n8n/extension-sdk/tsup.config.ts @@ -2,7 +2,16 @@ import { defineConfig } from 'tsup'; export default defineConfig([ { - clean: true, + clean: false, + entry: ['src/index.ts'], + outDir: 'dist', + format: ['cjs', 'esm'], + dts: true, + sourcemap: true, + tsconfig: 'tsconfig.json', + }, + { + clean: false, entry: [ 'src/backend/**/*.ts', '!src/backend/**/*.test.ts', @@ -16,7 +25,7 @@ export default defineConfig([ tsconfig: 'tsconfig.backend.json', }, { - clean: true, + clean: false, entry: [ 'src/frontend/**/*.ts', '!src/frontend/**/*.test.ts', diff --git a/packages/extensions/insights/.gitignore b/packages/extensions/insights/.gitignore new file mode 100644 index 0000000000..a547bf36d8 --- /dev/null +++ b/packages/extensions/insights/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/packages/extensions/insights/LICENSE b/packages/extensions/insights/LICENSE new file mode 100644 index 0000000000..54129160b9 --- /dev/null +++ b/packages/extensions/insights/LICENSE @@ -0,0 +1 @@ +See LICENSE.md in the root of this repository for more information. diff --git a/packages/extensions/insights/README.md b/packages/extensions/insights/README.md new file mode 100644 index 0000000000..b228d91581 --- /dev/null +++ b/packages/extensions/insights/README.md @@ -0,0 +1 @@ +# @n8n/n8n-extension-insights diff --git a/packages/extensions/insights/n8n.manifest.json b/packages/extensions/insights/n8n.manifest.json new file mode 100644 index 0000000000..cbeb9d4de5 --- /dev/null +++ b/packages/extensions/insights/n8n.manifest.json @@ -0,0 +1,23 @@ +{ + "name": "@n8n/n8n-extension-insights", + "version": "1.0.0", + "author": "n8n", + "category": "Internal", + "minSDKVersion": "0.0.0", + "permissions": { + "frontend": [], + "backend": [] + }, + "events": ["workflow:started"], + "setup": { + "backend": "./dist/backend/index.js", + "frontend": "./dist/frontend/index.js" + }, + "extends": { + "views": { + "workflows": { + "header": "InsightsDashboard" + } + } + } +} diff --git a/packages/extensions/insights/package.json b/packages/extensions/insights/package.json new file mode 100644 index 0000000000..6c8a27a64a --- /dev/null +++ b/packages/extensions/insights/package.json @@ -0,0 +1,56 @@ +{ + "name": "@n8n/n8n-extension-insights", + "version": "0.0.0", + "type": "module", + "files": [ + "dist", + "n8n.manifest.json", + "LICENSE", + "README.md" + ], + "main": "./n8n.manifest.json", + "module": "./n8n.manifest.json", + "exports": { + ".": { + "import": "./n8n.manifest.json", + "require": "./n8n.manifest.json" + }, + "./backend": { + "types": "./dist/backend/index.d.ts", + "import": "./dist/backend/index.js", + "require": "./dist/backend/index.cjs" + }, + "./frontend": { + "types": "./dist/frontend/index.d.ts", + "import": "./dist/frontend/index.js", + "require": "./dist/frontend/index.umd.cjs" + }, + "./*": "./*" + }, + "scripts": { + "cleanup": "rimraf dist", + "dev": "vite", + "typecheck": "vue-tsc --noEmit", + "build:backend": "tsup", + "build:frontend": "vite build", + "build": "pnpm cleanup && pnpm run \"/^build:.*/\"", + "preview": "vite preview" + }, + "peerDependencies": { + "vue": "catalog:frontend", + "vue-router": "catalog:frontend" + }, + "dependencies": { + "@n8n/extension-sdk": "workspace:*" + }, + "devDependencies": { + "@n8n/typescript-config": "workspace:*", + "@vitejs/plugin-vue": "catalog:frontend", + "@vue/tsconfig": "catalog:frontend", + "rimraf": "catalog:", + "vite": "catalog:frontend", + "vue": "catalog:frontend", + "vue-router": "catalog:frontend", + "vue-tsc": "catalog:frontend" + } +} diff --git a/packages/extensions/insights/src/backend/index.ts b/packages/extensions/insights/src/backend/index.ts new file mode 100644 index 0000000000..8340e2ac49 --- /dev/null +++ b/packages/extensions/insights/src/backend/index.ts @@ -0,0 +1,7 @@ +import { defineBackendExtension } from '@n8n/extension-sdk/backend'; + +export default defineBackendExtension({ + setup(n8n) { + console.log(n8n); + }, +}); diff --git a/packages/extensions/insights/src/frontend/InsightsDashboard.vue b/packages/extensions/insights/src/frontend/InsightsDashboard.vue new file mode 100644 index 0000000000..0e07c9b573 --- /dev/null +++ b/packages/extensions/insights/src/frontend/InsightsDashboard.vue @@ -0,0 +1,6 @@ + + diff --git a/packages/extensions/insights/src/frontend/index.ts b/packages/extensions/insights/src/frontend/index.ts new file mode 100644 index 0000000000..ab2ebe93b4 --- /dev/null +++ b/packages/extensions/insights/src/frontend/index.ts @@ -0,0 +1,9 @@ +import { markRaw } from 'vue'; +import { defineFrontendExtension } from '@n8n/extension-sdk/frontend'; +import InsightsDashboard from './InsightsDashboard.vue'; + +export default defineFrontendExtension({ + setup(n8n) { + n8n.registerComponent('InsightsDashboard', markRaw(InsightsDashboard)); + }, +}); diff --git a/packages/extensions/insights/src/shims.d.ts b/packages/extensions/insights/src/shims.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/packages/extensions/insights/src/shims.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/extensions/insights/tsconfig.backend.json b/packages/extensions/insights/tsconfig.backend.json new file mode 100644 index 0000000000..d19c6dc8e7 --- /dev/null +++ b/packages/extensions/insights/tsconfig.backend.json @@ -0,0 +1,9 @@ +{ + "extends": "@n8n/typescript-config/tsconfig.common.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "moduleResolution": "bundler", + "module": "esnext" + }, + "include": ["src/backend/**/*.ts", "src/index.ts"] +} diff --git a/packages/extensions/insights/tsconfig.frontend.json b/packages/extensions/insights/tsconfig.frontend.json new file mode 100644 index 0000000000..24f039ba21 --- /dev/null +++ b/packages/extensions/insights/tsconfig.frontend.json @@ -0,0 +1,7 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo" + }, + "include": ["src/frontend/**/*.ts", "src/frontend/**/*.vue"] +} diff --git a/packages/extensions/insights/tsconfig.json b/packages/extensions/insights/tsconfig.json new file mode 100644 index 0000000000..24286853de --- /dev/null +++ b/packages/extensions/insights/tsconfig.json @@ -0,0 +1,8 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.backend.json" }, + { "path": "./tsconfig.frontend.json" }, + { "path": "./tsconfig.vite.json" } + ] +} diff --git a/packages/extensions/insights/tsconfig.vite.json b/packages/extensions/insights/tsconfig.vite.json new file mode 100644 index 0000000000..624d886c18 --- /dev/null +++ b/packages/extensions/insights/tsconfig.vite.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/packages/extensions/insights/tsup.config.ts b/packages/extensions/insights/tsup.config.ts new file mode 100644 index 0000000000..c29e1bdbb4 --- /dev/null +++ b/packages/extensions/insights/tsup.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: [ + 'src/backend/**/*.ts', + '!src/backend/**/*.test.ts', + '!src/backend/**/*.d.ts', + '!src/backend/__tests__**/*', + ], + outDir: 'dist/backend', + format: ['cjs', 'esm'], + dts: true, + sourcemap: true, + tsconfig: 'tsconfig.backend.json', +}); diff --git a/packages/extensions/insights/vite.config.ts b/packages/extensions/insights/vite.config.ts new file mode 100644 index 0000000000..2b9bc8eb7d --- /dev/null +++ b/packages/extensions/insights/vite.config.ts @@ -0,0 +1,42 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import dts from 'vite-plugin-dts'; +import { configDefaults as vitestConfig } from 'vitest/config'; + +const cwd = process.cwd(); + +export default defineConfig({ + plugins: [ + vue(), + dts({ + rollupTypes: true, + tsconfigPath: resolve(cwd, 'tsconfig.frontend.json'), + }), + ], + build: { + emptyOutDir: false, + outDir: resolve(cwd, 'dist', 'frontend'), + lib: { + entry: resolve(cwd, 'src', 'frontend', 'index.ts'), + name: 'n8nFrontEndSdk', + fileName: 'index', + }, + rollupOptions: { + external: ['vue'], + output: { + preserveModules: false, + globals: { + vue: 'Vue', + }, + }, + }, + }, + test: { + globals: true, + environment: 'jsdom', + setupFiles: ['src/__tests__/setup.ts'], + include: ['src/**/*.spec.ts'], + exclude: vitestConfig.exclude, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a6f84fc806..33ee139637 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1348,6 +1348,37 @@ importers: specifier: 'catalog:' version: 0.4.14 + packages/extensions/insights: + dependencies: + '@n8n/extension-sdk': + specifier: workspace:* + version: link:../../@n8n/extension-sdk + devDependencies: + '@n8n/typescript-config': + specifier: workspace:* + version: link:../../@n8n/typescript-config + '@vitejs/plugin-vue': + specifier: catalog:frontend + version: 5.2.1(vite@6.2.1(@types/node@18.16.16)(jiti@1.21.0)(sass@1.64.1)(terser@5.16.1))(vue@3.5.13(typescript@5.8.2)) + '@vue/tsconfig': + specifier: catalog:frontend + version: 0.7.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)) + rimraf: + specifier: 'catalog:' + version: 6.0.1 + vite: + specifier: catalog:frontend + version: 6.2.1(@types/node@18.16.16)(jiti@1.21.0)(sass@1.64.1)(terser@5.16.1) + vue: + specifier: catalog:frontend + version: 3.5.13(typescript@5.8.2) + vue-router: + specifier: catalog:frontend + version: 4.5.0(vue@3.5.13(typescript@5.8.2)) + vue-tsc: + specifier: ^2.2.8 + version: 2.2.8(patch_hash=e2aee939ccac8a57fe449bfd92bedd8117841579526217bc39aca26c6b8c317f)(typescript@5.8.2) + packages/frontend/@n8n/chat: dependencies: '@vueuse/core': @@ -26033,8 +26064,6 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 - ret@0.1.15: {} - retry-axios@2.6.0(axios@1.8.2): dependencies: axios: 1.8.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8e083b85f9..0fdd5b72e7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,7 @@ packages: - packages/* - packages/@n8n/* - packages/frontend/** + - packages/extensions/** - cypress catalog: