@directus/extensions-sdk 12.1.4 → 13.0.1
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/dist/cli/commands/validate.d.ts +6 -0
- package/dist/cli/commands/validate.js +43 -0
- package/dist/cli/commands/validators/check-built-code.d.ts +7 -0
- package/dist/cli/commands/validators/check-built-code.js +48 -0
- package/dist/cli/commands/validators/check-directus-config.d.ts +7 -0
- package/dist/cli/commands/validators/check-directus-config.js +84 -0
- package/dist/cli/commands/validators/check-license.d.ts +7 -0
- package/dist/cli/commands/validators/check-license.js +26 -0
- package/dist/cli/commands/validators/check-readme.d.ts +7 -0
- package/dist/cli/commands/validators/check-readme.js +34 -0
- package/dist/cli/commands/validators/index.d.ts +5 -0
- package/dist/cli/commands/validators/index.js +5 -0
- package/dist/cli/run.js +7 -0
- package/dist/cli/types.d.ts +4 -0
- package/license +1 -1
- package/package.json +19 -17
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { log } from '../utils/logger.js';
|
|
4
|
+
import validators from './validators/index.js';
|
|
5
|
+
const printReport = (reports) => {
|
|
6
|
+
reports
|
|
7
|
+
.sort((a, b) => a.message.localeCompare(b.message))
|
|
8
|
+
.forEach(({ level, message }) => {
|
|
9
|
+
log(message, level);
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
export default async function validate(options) {
|
|
13
|
+
const spinner = ora(chalk.bold('Validating Directus extension...')).start();
|
|
14
|
+
const reports = [];
|
|
15
|
+
try {
|
|
16
|
+
const filteredValidators = validators.filter((value) => {
|
|
17
|
+
if (options.check) {
|
|
18
|
+
return options.check.toLowerCase() === value.name.toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
});
|
|
22
|
+
if (filteredValidators.length === 0) {
|
|
23
|
+
throw new Error(`No validator selected`);
|
|
24
|
+
}
|
|
25
|
+
const result = await Promise.allSettled(filteredValidators.map((value) => value.handler(spinner, reports)));
|
|
26
|
+
const rejectedChecks = result.filter((value) => value.status === 'rejected');
|
|
27
|
+
if (rejectedChecks.length > 0) {
|
|
28
|
+
spinner.fail(chalk.bold('Failed validation: '));
|
|
29
|
+
printReport(reports);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
spinner.succeed(chalk.bold('Extension is valid'));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
spinner.fail(chalk.bold('Failed validation: '));
|
|
38
|
+
log(String(error), 'error');
|
|
39
|
+
}
|
|
40
|
+
if (options.verbose ?? false) {
|
|
41
|
+
printReport(reports);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { EXTENSION_PKG_KEY } from '@directus/extensions';
|
|
2
|
+
import fse from 'fs-extra';
|
|
3
|
+
import {} from 'ora';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
const checkBuiltCode = {
|
|
6
|
+
name: 'built-code',
|
|
7
|
+
handler: async (spinner, reports) => {
|
|
8
|
+
spinner.text = 'Check for built code';
|
|
9
|
+
let codePath = '/dist';
|
|
10
|
+
const packagePath = path.resolve('package.json');
|
|
11
|
+
if (await fse.pathExists(packagePath)) {
|
|
12
|
+
const packageFile = await fse.readJson(packagePath);
|
|
13
|
+
if (packageFile[EXTENSION_PKG_KEY]) {
|
|
14
|
+
const { path } = packageFile[EXTENSION_PKG_KEY];
|
|
15
|
+
if (path) {
|
|
16
|
+
const message = `Path ${path} found in ${EXTENSION_PKG_KEY}`;
|
|
17
|
+
spinner.text = message;
|
|
18
|
+
reports.push({
|
|
19
|
+
level: 'info',
|
|
20
|
+
message: `${checkBuiltCode.name}: ${message}`,
|
|
21
|
+
});
|
|
22
|
+
codePath = path;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (typeof codePath === 'string') {
|
|
27
|
+
codePath = { app: codePath };
|
|
28
|
+
}
|
|
29
|
+
Object.keys(codePath).forEach(async (key) => {
|
|
30
|
+
if (!(await fse.pathExists(path.resolve(codePath[key])))) {
|
|
31
|
+
spinner.fail();
|
|
32
|
+
const message = `No ${codePath[key]} directory`;
|
|
33
|
+
reports.push({
|
|
34
|
+
level: 'error',
|
|
35
|
+
message: `${checkBuiltCode.name}: ${message}`,
|
|
36
|
+
});
|
|
37
|
+
throw new Error(message);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const message = 'Valid built code directory';
|
|
41
|
+
reports.push({
|
|
42
|
+
level: 'info',
|
|
43
|
+
message: `${checkBuiltCode.name}: ${message}`,
|
|
44
|
+
});
|
|
45
|
+
return (spinner.text = message);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
export default checkBuiltCode;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { EXTENSION_PKG_KEY, EXTENSION_TYPES, API_EXTENSION_TYPES } from '@directus/extensions';
|
|
2
|
+
import fse from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import {} from 'ora';
|
|
5
|
+
import semver from 'semver';
|
|
6
|
+
const checkDirectusConfig = {
|
|
7
|
+
name: 'directus-config',
|
|
8
|
+
handler: async (spinner, reports) => {
|
|
9
|
+
spinner.text = 'Checking package file exists';
|
|
10
|
+
const packagePath = path.resolve('package.json');
|
|
11
|
+
if (!(await fse.pathExists(packagePath))) {
|
|
12
|
+
spinner.fail();
|
|
13
|
+
const message = 'No package.json';
|
|
14
|
+
reports.push({
|
|
15
|
+
level: 'error',
|
|
16
|
+
message: `${checkDirectusConfig.name}: ${message}`,
|
|
17
|
+
});
|
|
18
|
+
throw new Error(message);
|
|
19
|
+
}
|
|
20
|
+
const packageFile = await fse.readJson(packagePath);
|
|
21
|
+
spinner.text = `Checking ${EXTENSION_PKG_KEY} is present`;
|
|
22
|
+
if (!packageFile[EXTENSION_PKG_KEY]) {
|
|
23
|
+
spinner.fail();
|
|
24
|
+
const message = `"${EXTENSION_PKG_KEY}" not found in ${packagePath}`;
|
|
25
|
+
reports.push({
|
|
26
|
+
level: 'error',
|
|
27
|
+
message: `${checkDirectusConfig.name}: ${message}`,
|
|
28
|
+
});
|
|
29
|
+
throw new Error(message);
|
|
30
|
+
}
|
|
31
|
+
const packageObject = packageFile[EXTENSION_PKG_KEY];
|
|
32
|
+
const { type, host, sandbox } = packageObject;
|
|
33
|
+
let extensionPath = packageObject.path;
|
|
34
|
+
spinner.text = `Checking extension type`;
|
|
35
|
+
if (!EXTENSION_TYPES.includes(type)) {
|
|
36
|
+
spinner.fail();
|
|
37
|
+
const message = `Invalid Directus Extension Type: ${type}`;
|
|
38
|
+
reports.push({
|
|
39
|
+
level: 'error',
|
|
40
|
+
message: `${checkDirectusConfig.name}: ${message}`,
|
|
41
|
+
});
|
|
42
|
+
throw new Error(message);
|
|
43
|
+
}
|
|
44
|
+
spinner.text = `Checking extension path(s)`;
|
|
45
|
+
if (typeof extensionPath === 'string') {
|
|
46
|
+
extensionPath = { app: extensionPath };
|
|
47
|
+
}
|
|
48
|
+
Object.keys(extensionPath).forEach(async (key) => {
|
|
49
|
+
if (!(await fse.pathExists(path.resolve(extensionPath[key])))) {
|
|
50
|
+
spinner.fail();
|
|
51
|
+
const message = `Extension path ${key}: ${extensionPath[key]} invalid`;
|
|
52
|
+
reports.push({
|
|
53
|
+
level: 'error',
|
|
54
|
+
message: `${checkDirectusConfig.name}: ${message}`,
|
|
55
|
+
});
|
|
56
|
+
throw new Error(message);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
spinner.text = 'Checking for valid Directus host version';
|
|
60
|
+
if (!semver.validRange(host)) {
|
|
61
|
+
spinner.fail();
|
|
62
|
+
const message = `${host} not a valid Directus version`;
|
|
63
|
+
reports.push({
|
|
64
|
+
level: 'error',
|
|
65
|
+
message: `${checkDirectusConfig.name}: ${message}`,
|
|
66
|
+
});
|
|
67
|
+
throw new Error(message);
|
|
68
|
+
}
|
|
69
|
+
spinner.text = 'Checking if it will publish to the Directus Marketplace';
|
|
70
|
+
if (type === 'bundle' || (sandbox && !sandbox?.enabled && API_EXTENSION_TYPES.findIndex(type) >= 0)) {
|
|
71
|
+
reports.push({
|
|
72
|
+
level: 'warn',
|
|
73
|
+
message: `${checkDirectusConfig.name}: Extension won't be generally visible in the Directus Marketplace`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const message = `Valid ${EXTENSION_PKG_KEY} Object`;
|
|
77
|
+
reports.push({
|
|
78
|
+
level: 'info',
|
|
79
|
+
message: `${checkDirectusConfig.name}: ${message}`,
|
|
80
|
+
});
|
|
81
|
+
return (spinner.text = message);
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
export default checkDirectusConfig;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fse from 'fs-extra';
|
|
2
|
+
import {} from 'ora';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
const checkLicense = {
|
|
5
|
+
name: 'license',
|
|
6
|
+
handler: async (spinner, reports) => {
|
|
7
|
+
spinner.text = 'Check for license';
|
|
8
|
+
const packagePath = path.resolve('package.json');
|
|
9
|
+
const { license } = await fse.readJson(packagePath);
|
|
10
|
+
if (!license) {
|
|
11
|
+
const message = 'No license defined';
|
|
12
|
+
reports.push({
|
|
13
|
+
level: 'error',
|
|
14
|
+
message: `${checkLicense.name}: ${message}`,
|
|
15
|
+
});
|
|
16
|
+
throw new Error(message);
|
|
17
|
+
}
|
|
18
|
+
const message = 'Valid license';
|
|
19
|
+
reports.push({
|
|
20
|
+
level: 'info',
|
|
21
|
+
message: `${checkLicense.name}: ${message}`,
|
|
22
|
+
});
|
|
23
|
+
return (spinner.text = message);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export default checkLicense;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { opendir } from 'node:fs/promises';
|
|
2
|
+
import {} from 'ora';
|
|
3
|
+
const checkReadMe = {
|
|
4
|
+
name: 'readme',
|
|
5
|
+
handler: async (spinner, reports) => {
|
|
6
|
+
spinner.text = 'Check for readme';
|
|
7
|
+
if (!(await hasReadmeFile())) {
|
|
8
|
+
spinner.fail();
|
|
9
|
+
const message = 'No readme file found';
|
|
10
|
+
reports.push({
|
|
11
|
+
level: 'error',
|
|
12
|
+
message: `${checkReadMe.name}: ${message}`,
|
|
13
|
+
});
|
|
14
|
+
throw new Error(message);
|
|
15
|
+
}
|
|
16
|
+
const message = 'Valid readme';
|
|
17
|
+
reports.push({
|
|
18
|
+
level: 'info',
|
|
19
|
+
message: `${checkReadMe.name}: ${message}`,
|
|
20
|
+
});
|
|
21
|
+
return (spinner.text = message);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
async function hasReadmeFile() {
|
|
25
|
+
/** README can have any case and extension */
|
|
26
|
+
const README_FILE_REGEX = /readme(\..+)?/i;
|
|
27
|
+
const dir = await opendir(process.cwd());
|
|
28
|
+
for await (const dirent of dir) {
|
|
29
|
+
if (dirent.isFile() && README_FILE_REGEX.test(dirent.name))
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
export default checkReadMe;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import checkReadme from './check-readme.js';
|
|
2
|
+
import checkLicense from './check-license.js';
|
|
3
|
+
import checkDirectusConfig from './check-directus-config.js';
|
|
4
|
+
import checkBuiltCode from './check-built-code.js';
|
|
5
|
+
export default [checkReadme, checkLicense, checkDirectusConfig, checkBuiltCode];
|
package/dist/cli/run.js
CHANGED
|
@@ -3,6 +3,7 @@ import add from './commands/add.js';
|
|
|
3
3
|
import build from './commands/build.js';
|
|
4
4
|
import create from './commands/create.js';
|
|
5
5
|
import link from './commands/link.js';
|
|
6
|
+
import validate from './commands/validate.js';
|
|
6
7
|
import getSdkVersion from './utils/get-sdk-version.js';
|
|
7
8
|
const program = new Command();
|
|
8
9
|
program.name('directus-extension').usage('[command] [options]');
|
|
@@ -36,4 +37,10 @@ program
|
|
|
36
37
|
.description('Creates a symlink to the extension in the Directus extensions folder')
|
|
37
38
|
.argument('<path>', 'path to the extension folder of directus')
|
|
38
39
|
.action(link);
|
|
40
|
+
program
|
|
41
|
+
.command('validate')
|
|
42
|
+
.description('Validate the extension against the Directus extensions requirements')
|
|
43
|
+
.option('-c, --check <check>', 'check a specific extension requirement')
|
|
44
|
+
.option('-v --verbose', 'print the full validation report')
|
|
45
|
+
.action(validate);
|
|
39
46
|
program.parse(process.argv);
|
package/dist/cli/types.d.ts
CHANGED
package/license
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
3
|
+
Copyright 2025 Monospace, Inc.
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
6
6
|
documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/extensions-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.1",
|
|
4
4
|
"description": "A toolkit to develop extensions to extend Directus",
|
|
5
5
|
"homepage": "https://directus.io",
|
|
6
6
|
"repository": {
|
|
@@ -28,37 +28,39 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@rollup/plugin-commonjs": "25.0.8",
|
|
30
30
|
"@rollup/plugin-json": "6.1.0",
|
|
31
|
-
"@rollup/plugin-node-resolve": "15.3.
|
|
31
|
+
"@rollup/plugin-node-resolve": "15.3.1",
|
|
32
32
|
"@rollup/plugin-replace": "5.0.7",
|
|
33
33
|
"@rollup/plugin-terser": "0.4.4",
|
|
34
34
|
"@rollup/plugin-virtual": "3.0.2",
|
|
35
35
|
"@vitejs/plugin-vue": "4.6.2",
|
|
36
|
-
"chalk": "5.
|
|
36
|
+
"chalk": "5.4.1",
|
|
37
37
|
"commander": "10.0.1",
|
|
38
38
|
"esbuild": "0.17.19",
|
|
39
39
|
"execa": "7.2.0",
|
|
40
40
|
"fs-extra": "11.2.0",
|
|
41
|
-
"inquirer": "12.
|
|
41
|
+
"inquirer": "12.3.0",
|
|
42
42
|
"ora": "6.3.1",
|
|
43
|
-
"rollup": "3.29.
|
|
43
|
+
"rollup": "3.29.5",
|
|
44
44
|
"rollup-plugin-esbuild": "5.0.0",
|
|
45
45
|
"rollup-plugin-styles": "4.0.0",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"@directus/
|
|
50
|
-
"@directus/extensions": "
|
|
51
|
-
"@directus/
|
|
52
|
-
"@directus/
|
|
53
|
-
"@directus/
|
|
46
|
+
"semver": "7.6.3",
|
|
47
|
+
"vite": "4.5.5",
|
|
48
|
+
"vue": "3.5.13",
|
|
49
|
+
"@directus/composables": "11.1.6",
|
|
50
|
+
"@directus/extensions": "3.0.1",
|
|
51
|
+
"@directus/constants": "13.0.0",
|
|
52
|
+
"@directus/themes": "1.0.7",
|
|
53
|
+
"@directus/types": "13.0.0",
|
|
54
|
+
"@directus/utils": "13.0.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
57
|
+
"@directus/tsconfig": "3.0.0",
|
|
56
58
|
"@types/fs-extra": "11.0.4",
|
|
57
59
|
"@types/inquirer": "9.0.7",
|
|
58
|
-
"@
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
60
|
+
"@types/semver": "7.5.8",
|
|
61
|
+
"@vitest/coverage-v8": "2.1.8",
|
|
62
|
+
"typescript": "5.7.3",
|
|
63
|
+
"vitest": "2.1.8"
|
|
62
64
|
},
|
|
63
65
|
"engines": {
|
|
64
66
|
"node": ">=12.20.0"
|