first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
+24
View File
@@ -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?
+1
View File
@@ -0,0 +1 @@
See LICENSE.md in the root of this repository for more information.
+1
View File
@@ -0,0 +1 @@
# @n8n/plugin-sdk
@@ -0,0 +1,14 @@
import { defineConfig } from 'eslint/config';
import { baseConfig } from '@n8n/eslint-config/base';
export default defineConfig(baseConfig, {
rules: {
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
// TODO: Remove this
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn',
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
'@typescript-eslint/no-floating-promises': 'warn',
'import-x/order': 'warn',
},
});
+63
View File
@@ -0,0 +1,63 @@
{
"name": "@n8n/extension-sdk",
"version": "0.9.0",
"type": "module",
"files": [
"dist",
"schema.json",
"LICENSE",
"README.md"
],
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./backend": {
"types": "./dist/backend/index.d.mts",
"import": "./dist/backend/index.mjs",
"require": "./dist/backend/index.cjs"
},
"./frontend": {
"types": "./dist/frontend/index.d.mts",
"import": "./dist/frontend/index.mjs",
"require": "./dist/frontend/index.cjs"
},
"./*": "./*"
},
"scripts": {
"clean": "rimraf dist",
"dev": "tsdown --watch",
"lint": "eslint . --quiet",
"typecheck:frontend": "vue-tsc --noEmit --project tsconfig.frontend.json",
"typecheck:backend": "tsc --noEmit --project tsconfig.backend.json",
"build": "pnpm \"/^typecheck:.+/\" && pnpm clean && tsdown && pnpm create-json-schema",
"create-json-schema": "tsx scripts/create-json-schema.ts",
"preview": "vite preview"
},
"peerDependencies": {
"vue": "catalog:frontend",
"vue-router": "catalog:frontend"
},
"devDependencies": {
"@n8n/typescript-config": "workspace:*",
"@vitejs/plugin-vue": "catalog:frontend",
"@vue/tsconfig": "catalog:frontend",
"tsdown": "catalog:",
"rimraf": "catalog:",
"vite": "catalog:",
"vue": "catalog:frontend",
"vue-router": "catalog:frontend",
"vue-tsc": "catalog:frontend",
"zod-to-json-schema": "catalog:",
"tsx": "catalog:"
},
"license": "https://docs.n8n.io/sustainable-use-license/",
"dependencies": {
"zod": "catalog:"
}
}
+64
View File
@@ -0,0 +1,64 @@
{
"type": "object",
"properties": {
"name": { "type": "string" },
"displayName": { "type": "string" },
"description": { "type": "string" },
"publisher": { "type": "string" },
"version": { "type": "string" },
"categories": { "type": "array", "items": { "type": "string" } },
"entry": {
"type": "object",
"properties": { "backend": { "type": "string" }, "frontend": { "type": "string" } },
"required": ["backend", "frontend"],
"additionalProperties": false
},
"minSDKVersion": { "type": "string" },
"permissions": {
"type": "object",
"properties": {
"frontend": { "type": "array", "items": { "type": "string" } },
"backend": { "type": "array", "items": { "type": "string" } }
},
"required": ["frontend", "backend"],
"additionalProperties": false
},
"events": { "type": "array", "items": { "type": "string" } },
"extends": {
"type": "object",
"properties": {
"views": {
"type": "object",
"properties": {
"workflows": {
"type": "object",
"properties": { "header": { "type": "string" } },
"required": ["header"],
"additionalProperties": false
}
},
"required": ["workflows"],
"additionalProperties": false
}
},
"required": ["views"],
"additionalProperties": false
}
},
"required": [
"name",
"displayName",
"description",
"publisher",
"version",
"categories",
"entry",
"minSDKVersion",
"permissions",
"events",
"extends"
],
"additionalProperties": false,
"title": "N8nExtensionSchema",
"$schema": "http://json-schema.org/draft-07/schema#"
}
@@ -0,0 +1,22 @@
import { extensionManifestSchema } from '../src/schema';
import { zodToJsonSchema } from 'zod-to-json-schema';
import { writeFile } from 'fs/promises';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
import { format, resolveConfig } from 'prettier';
const __dirname = dirname(fileURLToPath(import.meta.url));
const rootDir = resolve(__dirname, '..');
const jsonSchema = zodToJsonSchema(extensionManifestSchema, {
name: 'N8nExtensionSchema',
nameStrategy: 'title',
});
(async () => {
const filepath = 'schema.json';
const schema = JSON.stringify(jsonSchema);
const config = await resolveConfig(filepath);
const formattedSchema = await format(schema, { ...config, filepath });
await writeFile(resolve(rootDir, filepath), formattedSchema);
})();
@@ -0,0 +1,5 @@
import type { BackendExtension } from './types.ts';
export function defineBackendExtension(extension: BackendExtension): BackendExtension {
return extension;
}
@@ -0,0 +1,2 @@
export * from './define';
export type * from './types';
@@ -0,0 +1,9 @@
export type BackendExtensionContext = {
example?: string;
};
export type BackendExtensionSetupFn = (context: BackendExtension) => void;
export type BackendExtension = {
setup: BackendExtensionSetupFn;
};
@@ -0,0 +1,5 @@
import type { FrontendExtension } from './types.ts';
export function defineFrontendExtension(extension: FrontendExtension): FrontendExtension {
return extension;
}
@@ -0,0 +1,2 @@
export * from './define';
export type * from './types';
@@ -0,0 +1,14 @@
import type { RouteRecordRaw } from 'vue-router';
import type { App, Component } from 'vue';
export type FrontendExtensionContext = {
app: App;
defineRoutes: (routes: RouteRecordRaw[]) => void;
registerComponent: (name: string, component: Component) => void;
};
export type FrontendExtensionSetupFn = (context: FrontendExtensionContext) => void;
export type FrontendExtension = {
setup: FrontendExtensionSetupFn;
};
+1
View File
@@ -0,0 +1 @@
export * from './schema';
+96
View File
@@ -0,0 +1,96 @@
import { z } from 'zod';
/**
* Schema for the extension configuration.
*/
export const extensionManifestSchema = z.object({
/**
* Name of the extension package.
*/
name: z.string(),
/**
* The display name of the extension.
*/
displayName: z.string(),
/**
* Description of the extension package.
*/
description: z.string(),
/**
* Publisher of the extension.
*/
publisher: z.string(),
/**
* Version of the extension package.
*/
version: z.string(),
/**
* Category the extension belongs to.
*/
categories: z.array(z.string()),
/**
* Setup paths for backend and frontend code entry points.
*/
entry: z.object({
/**
* Path to the backend entry file.
*/
backend: z.string(),
/**
* Path to the frontend entry file.
*/
frontend: z.string(),
}),
/**
* Minimum SDK version required to run the extension.
*/
minSDKVersion: z.string(),
/**
* Permissions object specifying allowed access for frontend and backend.
*/
permissions: z.object({
/**
* List of frontend permissions (array of strings).
*/
frontend: z.array(z.string()),
/**
* List of backend permissions (array of strings).
*/
backend: z.array(z.string()),
}),
/**
* List of events that the extension listens to.
*/
events: z.array(z.string()),
/**
* Define extension points for existing functionalities.
*/
extends: z.object({
/**
* Extends the views configuration.
*/
views: z.object({
/**
* Extends the workflows view configuration.
*/
workflows: z.object({
/**
* Header component for the workflows view.
*/
header: z.string(),
}),
}),
}),
});
export type ExtensionManifest = z.infer<typeof extensionManifestSchema>;
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />
@@ -0,0 +1,9 @@
{
"extends": "@n8n/typescript-config/tsconfig.common.json",
"compilerOptions": {
"composite": true,
"declaration": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.backend.tsbuildinfo"
},
"include": ["src/backend/**/*.ts"]
}
@@ -0,0 +1,9 @@
{
"extends": "@n8n/typescript-config/tsconfig.common.json",
"compilerOptions": {
"composite": true,
"declaration": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.backend.tsbuildinfo"
},
"include": ["src/*.ts"]
}
@@ -0,0 +1,9 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"composite": true,
"declaration": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.frontend.tsbuildinfo"
},
"include": ["src/frontend/**/*.ts", "src/frontend/**/*.vue"]
}
+13
View File
@@ -0,0 +1,13 @@
{
"references": [
{
"path": "./tsconfig.common.json"
},
{
"path": "./tsconfig.backend.json"
},
{
"path": "./tsconfig.frontend.json"
}
]
}
@@ -0,0 +1,45 @@
import { defineConfig } from 'tsdown';
// eslint-disable-next-line import-x/no-default-export
export default defineConfig([
{
clean: false,
entry: ['src/*.ts', '!src/*.test.ts', '!src/*.d.ts', '!src/__tests__/**/*'],
outDir: 'dist',
format: ['cjs', 'esm'],
dts: true,
sourcemap: true,
tsconfig: 'tsconfig.common.json',
hash: false,
},
{
clean: false,
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',
hash: false,
},
{
clean: false,
entry: [
'src/frontend/**/*.ts',
'!src/frontend/**/*.test.ts',
'!src/frontend/**/*.d.ts',
'!src/frontend/__tests__/**/*',
],
outDir: 'dist/frontend',
format: ['cjs', 'esm'],
dts: true,
sourcemap: true,
tsconfig: 'tsconfig.frontend.json',
hash: false,
},
]);