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
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:
@@ -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?
|
||||
@@ -0,0 +1 @@
|
||||
See LICENSE.md in the root of this repository for more information.
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
@@ -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:"
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './schema';
|
||||
@@ -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
@@ -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"]
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
]);
|
||||
Reference in New Issue
Block a user