directus 9.22.1 → 9.22.4
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/controllers/extensions.js +4 -4
- package/dist/controllers/utils.js +4 -1
- package/dist/database/helpers/fn/dialects/mysql.d.ts +8 -8
- package/dist/database/helpers/fn/dialects/mysql.js +16 -22
- package/dist/database/helpers/schema/dialects/mssql.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/mssql.js +10 -0
- package/dist/database/helpers/schema/dialects/mysql.js +1 -1
- package/dist/database/helpers/schema/types.d.ts +1 -0
- package/dist/database/helpers/schema/types.js +6 -1
- package/dist/database/run-ast.js +16 -26
- package/dist/env.js +2 -0
- package/dist/extensions.d.ts +3 -2
- package/dist/extensions.js +45 -19
- package/dist/flows.js +2 -0
- package/dist/operations/exec/index.js +3 -0
- package/dist/operations/item-create/index.test.d.ts +1 -0
- package/dist/operations/item-delete/index.js +1 -1
- package/dist/operations/item-delete/index.test.d.ts +1 -0
- package/dist/operations/item-read/index.js +1 -1
- package/dist/operations/item-read/index.test.d.ts +1 -0
- package/dist/operations/item-update/index.test.d.ts +1 -0
- package/dist/operations/log/index.test.d.ts +1 -0
- package/dist/operations/mail/index.js +4 -1
- package/dist/operations/notification/index.test.d.ts +1 -0
- package/dist/operations/request/index.test.d.ts +1 -0
- package/dist/operations/sleep/index.test.d.ts +1 -0
- package/dist/operations/transform/index.test.d.ts +1 -0
- package/dist/operations/trigger/index.test.d.ts +1 -0
- package/dist/services/import-export.js +2 -0
- package/dist/services/roles.js +1 -1
- package/dist/services/server.js +5 -2
- package/dist/utils/apply-function-to-column-name.test.d.ts +1 -0
- package/dist/utils/apply-query.d.ts +2 -2
- package/dist/utils/apply-query.js +4 -6
- package/dist/utils/get-cache-key.js +6 -7
- package/dist/utils/get-date-formatted.test.d.ts +1 -0
- package/dist/utils/get-graphql-query-and-variables.d.ts +2 -0
- package/dist/utils/get-graphql-query-and-variables.js +10 -0
- package/dist/utils/get-graphql-query-and-variables.test.d.ts +1 -0
- package/dist/utils/get-permissions.js +13 -6
- package/dist/utils/md.test.d.ts +1 -0
- package/dist/utils/sanitize-query.test.d.ts +1 -0
- package/dist/utils/stall.test.d.ts +1 -0
- package/dist/utils/strip-function.test.d.ts +1 -0
- package/dist/utils/user-name.test.d.ts +1 -0
- package/dist/utils/validate-env.test.d.ts +1 -0
- package/dist/utils/validate-query.js +3 -3
- package/package.json +50 -52
|
@@ -7,16 +7,16 @@ const express_1 = require("express");
|
|
|
7
7
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
8
8
|
const exceptions_1 = require("../exceptions");
|
|
9
9
|
const extensions_1 = require("../extensions");
|
|
10
|
-
const respond_1 = require("../middleware/respond");
|
|
11
|
-
const utils_1 = require("@directus/shared/utils");
|
|
12
|
-
const constants_1 = require("@directus/shared/constants");
|
|
13
10
|
const ms_1 = __importDefault(require("ms"));
|
|
14
11
|
const env_1 = __importDefault(require("../env"));
|
|
15
12
|
const get_cache_headers_1 = require("../utils/get-cache-headers");
|
|
13
|
+
const respond_1 = require("../middleware/respond");
|
|
14
|
+
const utils_1 = require("@directus/shared/utils");
|
|
15
|
+
const constants_1 = require("@directus/shared/constants");
|
|
16
16
|
const router = (0, express_1.Router)();
|
|
17
17
|
router.get('/:type', (0, async_handler_1.default)(async (req, res, next) => {
|
|
18
18
|
const type = (0, utils_1.depluralize)(req.params.type);
|
|
19
|
-
if (!(0, utils_1.isIn)(type, constants_1.
|
|
19
|
+
if (!(0, utils_1.isIn)(type, constants_1.EXTENSION_TYPES)) {
|
|
20
20
|
throw new exceptions_1.RouteNotFoundException(req.path);
|
|
21
21
|
}
|
|
22
22
|
const extensionManager = (0, extensions_1.getExtensionManager)();
|
|
@@ -14,6 +14,7 @@ const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
|
14
14
|
const busboy_1 = __importDefault(require("busboy"));
|
|
15
15
|
const cache_1 = require("../cache");
|
|
16
16
|
const generate_hash_1 = require("../utils/generate-hash");
|
|
17
|
+
const sanitize_query_1 = require("../utils/sanitize-query");
|
|
17
18
|
const router = (0, express_1.Router)();
|
|
18
19
|
router.get('/random/string', (0, async_handler_1.default)(async (req, res) => {
|
|
19
20
|
var _a;
|
|
@@ -96,6 +97,7 @@ router.post('/import/:collection', collection_exists_1.default, (0, async_handle
|
|
|
96
97
|
req.pipe(busboy);
|
|
97
98
|
}));
|
|
98
99
|
router.post('/export/:collection', collection_exists_1.default, (0, async_handler_1.default)(async (req, res, next) => {
|
|
100
|
+
var _a;
|
|
99
101
|
if (!req.body.query) {
|
|
100
102
|
throw new exceptions_1.InvalidPayloadException(`"query" is required.`);
|
|
101
103
|
}
|
|
@@ -106,8 +108,9 @@ router.post('/export/:collection', collection_exists_1.default, (0, async_handle
|
|
|
106
108
|
accountability: req.accountability,
|
|
107
109
|
schema: req.schema,
|
|
108
110
|
});
|
|
111
|
+
const sanitizedQuery = (0, sanitize_query_1.sanitizeQuery)(req.body.query, (_a = req.accountability) !== null && _a !== void 0 ? _a : null);
|
|
109
112
|
// We're not awaiting this, as it's supposed to run async in the background
|
|
110
|
-
service.exportToFile(req.params.collection,
|
|
113
|
+
service.exportToFile(req.params.collection, sanitizedQuery, req.body.format, {
|
|
111
114
|
file: req.body.file,
|
|
112
115
|
});
|
|
113
116
|
return next();
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { FnHelper, FnHelperOptions } from '../types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
3
|
export declare class FnHelperMySQL extends FnHelper {
|
|
4
|
-
year(table: string, column: string
|
|
5
|
-
month(table: string, column: string
|
|
6
|
-
week(table: string, column: string
|
|
7
|
-
day(table: string, column: string
|
|
8
|
-
weekday(table: string, column: string
|
|
9
|
-
hour(table: string, column: string
|
|
10
|
-
minute(table: string, column: string
|
|
11
|
-
second(table: string, column: string
|
|
4
|
+
year(table: string, column: string): Knex.Raw;
|
|
5
|
+
month(table: string, column: string): Knex.Raw;
|
|
6
|
+
week(table: string, column: string): Knex.Raw;
|
|
7
|
+
day(table: string, column: string): Knex.Raw;
|
|
8
|
+
weekday(table: string, column: string): Knex.Raw;
|
|
9
|
+
hour(table: string, column: string): Knex.Raw;
|
|
10
|
+
minute(table: string, column: string): Knex.Raw;
|
|
11
|
+
second(table: string, column: string): Knex.Raw;
|
|
12
12
|
count(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
13
13
|
}
|
|
@@ -2,36 +2,30 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FnHelperMySQL = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
|
-
const parseLocaltime = (columnType) => {
|
|
6
|
-
if (columnType === 'timestamp') {
|
|
7
|
-
return `CONVERT_TZ(??.??, @@GLOBAL.time_zone, '+00:00')`;
|
|
8
|
-
}
|
|
9
|
-
return '??.??';
|
|
10
|
-
};
|
|
11
5
|
class FnHelperMySQL extends types_1.FnHelper {
|
|
12
|
-
year(table, column
|
|
13
|
-
return this.knex.raw(
|
|
6
|
+
year(table, column) {
|
|
7
|
+
return this.knex.raw('YEAR(??.??)', [table, column]);
|
|
14
8
|
}
|
|
15
|
-
month(table, column
|
|
16
|
-
return this.knex.raw(
|
|
9
|
+
month(table, column) {
|
|
10
|
+
return this.knex.raw('MONTH(??.??)', [table, column]);
|
|
17
11
|
}
|
|
18
|
-
week(table, column
|
|
19
|
-
return this.knex.raw(
|
|
12
|
+
week(table, column) {
|
|
13
|
+
return this.knex.raw('WEEK(??.??)', [table, column]);
|
|
20
14
|
}
|
|
21
|
-
day(table, column
|
|
22
|
-
return this.knex.raw(
|
|
15
|
+
day(table, column) {
|
|
16
|
+
return this.knex.raw('DAYOFMONTH(??.??)', [table, column]);
|
|
23
17
|
}
|
|
24
|
-
weekday(table, column
|
|
25
|
-
return this.knex.raw(
|
|
18
|
+
weekday(table, column) {
|
|
19
|
+
return this.knex.raw('DAYOFWEEK(??.??)', [table, column]);
|
|
26
20
|
}
|
|
27
|
-
hour(table, column
|
|
28
|
-
return this.knex.raw(
|
|
21
|
+
hour(table, column) {
|
|
22
|
+
return this.knex.raw('HOUR(??.??)', [table, column]);
|
|
29
23
|
}
|
|
30
|
-
minute(table, column
|
|
31
|
-
return this.knex.raw(
|
|
24
|
+
minute(table, column) {
|
|
25
|
+
return this.knex.raw('MINUTE(??.??)', [table, column]);
|
|
32
26
|
}
|
|
33
|
-
second(table, column
|
|
34
|
-
return this.knex.raw(
|
|
27
|
+
second(table, column) {
|
|
28
|
+
return this.knex.raw('SECOND(??.??)', [table, column]);
|
|
35
29
|
}
|
|
36
30
|
count(table, column, options) {
|
|
37
31
|
var _a, _b, _c, _d, _e;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Knex } from 'knex';
|
|
2
2
|
import { SchemaHelper } from '../types';
|
|
3
3
|
export declare class SchemaHelperMSSQL extends SchemaHelper {
|
|
4
|
+
applyLimit(rootQuery: Knex.QueryBuilder, limit: number): void;
|
|
4
5
|
applyOffset(rootQuery: Knex.QueryBuilder, offset: number): void;
|
|
5
6
|
formatUUID(uuid: string): string;
|
|
6
7
|
}
|
|
@@ -3,6 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SchemaHelperMSSQL = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
class SchemaHelperMSSQL extends types_1.SchemaHelper {
|
|
6
|
+
applyLimit(rootQuery, limit) {
|
|
7
|
+
// The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries,
|
|
8
|
+
// and common table expressions, unless TOP, OFFSET or FOR XML is also specified.
|
|
9
|
+
if (limit === -1) {
|
|
10
|
+
rootQuery.limit(Number.MAX_SAFE_INTEGER);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
rootQuery.limit(limit);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
6
16
|
applyOffset(rootQuery, offset) {
|
|
7
17
|
rootQuery.offset(offset);
|
|
8
18
|
rootQuery.orderBy(1);
|
|
@@ -7,7 +7,7 @@ class SchemaHelperMySQL extends types_1.SchemaHelper {
|
|
|
7
7
|
applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields) {
|
|
8
8
|
var _a;
|
|
9
9
|
if ((_a = (0, database_1.getDatabaseVersion)()) === null || _a === void 0 ? void 0 : _a.startsWith('5.7')) {
|
|
10
|
-
dbQuery.orderByRaw(`?? asc, ${orderByString
|
|
10
|
+
dbQuery.orderByRaw(`?? asc, ${orderByString}`, [`${table}.${primaryKey}`, ...orderByFields]);
|
|
11
11
|
dbQuery = knex
|
|
12
12
|
.select(knex.raw(`??, ( @rank := IF ( @cur_id = deep.${primaryKey}, @rank + 1, 1 ) ) AS directus_row_number, ( @cur_id := deep.${primaryKey} ) AS current_id`, 'deep.*'))
|
|
13
13
|
.from(knex.raw('? as ??, (SELECT @rank := 0, @cur_id := null) vars', [dbQuery, 'deep']));
|
|
@@ -15,6 +15,7 @@ export declare abstract class SchemaHelper extends DatabaseHelper {
|
|
|
15
15
|
preColumnChange(): Promise<boolean>;
|
|
16
16
|
postColumnChange(): Promise<void>;
|
|
17
17
|
constraintName(existingName: string): string;
|
|
18
|
+
applyLimit(rootQuery: Knex.QueryBuilder, limit: number): void;
|
|
18
19
|
applyOffset(rootQuery: Knex.QueryBuilder, offset: number): void;
|
|
19
20
|
castA2oPrimaryKey(): string;
|
|
20
21
|
applyMultiRelationalSort(knex: Knex, dbQuery: Knex.QueryBuilder, table: string, primaryKey: string, orderByString: string, orderByFields: Knex.Raw[]): Knex.QueryBuilder;
|
|
@@ -67,6 +67,11 @@ class SchemaHelper extends types_1.DatabaseHelper {
|
|
|
67
67
|
// reference issue #14873
|
|
68
68
|
return existingName;
|
|
69
69
|
}
|
|
70
|
+
applyLimit(rootQuery, limit) {
|
|
71
|
+
if (limit !== -1) {
|
|
72
|
+
rootQuery.limit(limit);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
70
75
|
applyOffset(rootQuery, offset) {
|
|
71
76
|
rootQuery.offset(offset);
|
|
72
77
|
}
|
|
@@ -74,7 +79,7 @@ class SchemaHelper extends types_1.DatabaseHelper {
|
|
|
74
79
|
return 'CAST(?? AS CHAR(255))';
|
|
75
80
|
}
|
|
76
81
|
applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields) {
|
|
77
|
-
dbQuery.rowNumber(knex.ref('directus_row_number').toQuery(), knex.raw(`partition by
|
|
82
|
+
dbQuery.rowNumber(knex.ref('directus_row_number').toQuery(), knex.raw(`partition by ?? order by ${orderByString}`, [`${table}.${primaryKey}`, ...orderByFields]));
|
|
78
83
|
return dbQuery;
|
|
79
84
|
}
|
|
80
85
|
formatUUID(uuid) {
|
package/dist/database/run-ast.js
CHANGED
|
@@ -218,41 +218,29 @@ async function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
|
218
218
|
}
|
|
219
219
|
if (sortRecords) {
|
|
220
220
|
if (needsInnerQuery) {
|
|
221
|
+
let orderByString = '';
|
|
222
|
+
const orderByFields = [];
|
|
221
223
|
sortRecords.map((sortRecord) => {
|
|
224
|
+
if (orderByString.length !== 0) {
|
|
225
|
+
orderByString += ', ';
|
|
226
|
+
}
|
|
222
227
|
const sortAlias = `sort_${(0, apply_query_1.generateAlias)()}`;
|
|
223
228
|
if (sortRecord.column.includes('.')) {
|
|
224
229
|
const [alias, field] = sortRecord.column.split('.');
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
230
|
+
const originalCollectionName = (0, get_collection_from_alias_1.getCollectionFromAlias)(alias, aliasMap);
|
|
231
|
+
dbQuery.select((0, get_column_1.getColumn)(knex, alias, field, sortAlias, schema, { originalCollectionName }));
|
|
232
|
+
orderByString += `?? ${sortRecord.order}`;
|
|
233
|
+
orderByFields.push((0, get_column_1.getColumn)(knex, alias, field, false, schema, { originalCollectionName }));
|
|
228
234
|
}
|
|
229
235
|
else {
|
|
230
236
|
dbQuery.select((0, get_column_1.getColumn)(knex, table, sortRecord.column, sortAlias, schema));
|
|
237
|
+
orderByString += `?? ${sortRecord.order}`;
|
|
238
|
+
orderByFields.push((0, get_column_1.getColumn)(knex, table, sortRecord.column, false, schema));
|
|
231
239
|
}
|
|
232
240
|
innerQuerySortRecords.push({ alias: sortAlias, order: sortRecord.order });
|
|
233
241
|
});
|
|
242
|
+
dbQuery.orderByRaw(orderByString, orderByFields);
|
|
234
243
|
if (hasMultiRelationalSort) {
|
|
235
|
-
let orderByString = '';
|
|
236
|
-
const orderByFields = [];
|
|
237
|
-
sortRecords.map((sortRecord) => {
|
|
238
|
-
if (orderByString.length === 0) {
|
|
239
|
-
orderByString += ' order by';
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
orderByString += ',';
|
|
243
|
-
}
|
|
244
|
-
if (sortRecord.column.includes('.')) {
|
|
245
|
-
orderByString += ` ?? ${sortRecord.order}`;
|
|
246
|
-
const [alias, field] = sortRecord.column.split('.');
|
|
247
|
-
orderByFields.push((0, get_column_1.getColumn)(knex, alias, field, false, schema, {
|
|
248
|
-
originalCollectionName: (0, get_collection_from_alias_1.getCollectionFromAlias)(alias, aliasMap),
|
|
249
|
-
}));
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
orderByString += ` ?? ${sortRecord.order}`;
|
|
253
|
-
orderByFields.push((0, get_column_1.getColumn)(knex, table, sortRecord.column, false, schema));
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
244
|
dbQuery = helpers.schema.applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields);
|
|
257
245
|
}
|
|
258
246
|
}
|
|
@@ -285,7 +273,7 @@ async function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
|
285
273
|
});
|
|
286
274
|
if (hasMultiRelationalSort) {
|
|
287
275
|
wrapperQuery.where('inner.directus_row_number', '=', 1);
|
|
288
|
-
(0, apply_query_1.applyLimit)(wrapperQuery, queryCopy.limit);
|
|
276
|
+
(0, apply_query_1.applyLimit)(knex, wrapperQuery, queryCopy.limit);
|
|
289
277
|
}
|
|
290
278
|
}
|
|
291
279
|
return wrapperQuery;
|
|
@@ -452,7 +440,9 @@ function removeTemporaryFields(schema, rawItem, ast, primaryKeyField, parentItem
|
|
|
452
440
|
for (const nestedNode of nestedCollectionNodes[relatedCollection]) {
|
|
453
441
|
item[nestedNode.fieldKey] = removeTemporaryFields(schema, item[nestedNode.fieldKey], nestedNode, schema.collections[nestedNode.relation.collection].primary, item);
|
|
454
442
|
}
|
|
455
|
-
|
|
443
|
+
const fieldsWithFunctionsApplied = fields[relatedCollection].map((field) => (0, apply_function_to_column_name_1.applyFunctionToColumnName)(field));
|
|
444
|
+
item =
|
|
445
|
+
fields[relatedCollection].length > 0 ? (0, lodash_1.pick)(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField];
|
|
456
446
|
items.push(item);
|
|
457
447
|
}
|
|
458
448
|
}
|
package/dist/env.js
CHANGED
|
@@ -183,6 +183,7 @@ const allowedEnvironmentVars = [
|
|
|
183
183
|
'EXPORT_BATCH_SIZE',
|
|
184
184
|
// flows
|
|
185
185
|
'FLOWS_EXEC_ALLOWED_MODULES',
|
|
186
|
+
'FLOWS_ENV_ALLOW_LIST',
|
|
186
187
|
].map((name) => new RegExp(`^${name}$`));
|
|
187
188
|
const acceptedEnvTypes = ['string', 'number', 'regex', 'array', 'json'];
|
|
188
189
|
const defaults = {
|
|
@@ -247,6 +248,7 @@ const defaults = {
|
|
|
247
248
|
FILE_METADATA_ALLOW_LIST: 'ifd0.Make,ifd0.Model,exif.FNumber,exif.ExposureTime,exif.FocalLength,exif.ISO',
|
|
248
249
|
GRAPHQL_INTROSPECTION: true,
|
|
249
250
|
FLOWS_EXEC_ALLOWED_MODULES: false,
|
|
251
|
+
FLOWS_ENV_ALLOW_LIST: false,
|
|
250
252
|
};
|
|
251
253
|
// Allows us to force certain environment variable into a type, instead of relying
|
|
252
254
|
// on the auto-parsed type in processValues. ref #3705
|
package/dist/extensions.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExtensionType } from '@directus/shared/types';
|
|
1
|
+
import { Extension, ExtensionInfo, ExtensionType } from '@directus/shared/types';
|
|
2
2
|
import { Router } from 'express';
|
|
3
3
|
export declare function getExtensionManager(): ExtensionManager;
|
|
4
4
|
type Options = {
|
|
@@ -21,7 +21,8 @@ declare class ExtensionManager {
|
|
|
21
21
|
constructor();
|
|
22
22
|
initialize(options?: Partial<Options>): Promise<void>;
|
|
23
23
|
reload(): void;
|
|
24
|
-
getExtensionsList(type?: ExtensionType):
|
|
24
|
+
getExtensionsList(type?: ExtensionType): ExtensionInfo[];
|
|
25
|
+
getExtension(name: string): Extension | undefined;
|
|
25
26
|
getAppExtensions(): string | null;
|
|
26
27
|
getEndpointRouter(): Router;
|
|
27
28
|
getEmbeds(): {
|
package/dist/extensions.js
CHANGED
|
@@ -97,7 +97,7 @@ class ExtensionManager {
|
|
|
97
97
|
await this.load();
|
|
98
98
|
const loadedExtensions = this.getExtensionsList();
|
|
99
99
|
if (loadedExtensions.length > 0) {
|
|
100
|
-
logger_1.default.info(`Loaded extensions: ${loadedExtensions.join(', ')}`);
|
|
100
|
+
logger_1.default.info(`Loaded extensions: ${loadedExtensions.map((ext) => ext.name).join(', ')}`);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
if (!prevOptions.watch && this.options.watch) {
|
|
@@ -130,12 +130,36 @@ class ExtensionManager {
|
|
|
130
130
|
}
|
|
131
131
|
getExtensionsList(type) {
|
|
132
132
|
if (type === undefined) {
|
|
133
|
-
return this.extensions.map(
|
|
133
|
+
return this.extensions.map(mapInfo);
|
|
134
134
|
}
|
|
135
135
|
else {
|
|
136
|
-
return this.extensions.filter((extension) => extension.type === type)
|
|
136
|
+
return this.extensions.map(mapInfo).filter((extension) => extension.type === type);
|
|
137
|
+
}
|
|
138
|
+
function mapInfo(extension) {
|
|
139
|
+
const extensionInfo = {
|
|
140
|
+
name: extension.name,
|
|
141
|
+
type: extension.type,
|
|
142
|
+
local: extension.local,
|
|
143
|
+
host: extension.host,
|
|
144
|
+
version: extension.version,
|
|
145
|
+
};
|
|
146
|
+
if (extension.type === 'bundle') {
|
|
147
|
+
return {
|
|
148
|
+
...extensionInfo,
|
|
149
|
+
entries: extension.entries.map((entry) => ({
|
|
150
|
+
name: entry.name,
|
|
151
|
+
type: entry.type,
|
|
152
|
+
})),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
return extensionInfo;
|
|
157
|
+
}
|
|
137
158
|
}
|
|
138
159
|
}
|
|
160
|
+
getExtension(name) {
|
|
161
|
+
return this.extensions.find((extension) => extension.name === name);
|
|
162
|
+
}
|
|
139
163
|
getAppExtensions() {
|
|
140
164
|
return this.appExtensions;
|
|
141
165
|
}
|
|
@@ -155,7 +179,7 @@ class ExtensionManager {
|
|
|
155
179
|
}
|
|
156
180
|
async load() {
|
|
157
181
|
try {
|
|
158
|
-
await (0, node_1.ensureExtensionDirs)(env_1.default.EXTENSIONS_PATH,
|
|
182
|
+
await (0, node_1.ensureExtensionDirs)(env_1.default.EXTENSIONS_PATH, constants_1.NESTED_EXTENSION_TYPES);
|
|
159
183
|
this.extensions = await this.getExtensions();
|
|
160
184
|
}
|
|
161
185
|
catch (err) {
|
|
@@ -182,11 +206,14 @@ class ExtensionManager {
|
|
|
182
206
|
initializeWatcher() {
|
|
183
207
|
if (!this.watcher) {
|
|
184
208
|
logger_1.default.info('Watching extensions for changes...');
|
|
185
|
-
const localExtensionPaths =
|
|
209
|
+
const localExtensionPaths = constants_1.NESTED_EXTENSION_TYPES.flatMap((type) => {
|
|
186
210
|
const typeDir = path_1.default.posix.join((0, node_1.pathToRelativeUrl)(env_1.default.EXTENSIONS_PATH), (0, utils_1.pluralize)(type));
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
211
|
+
if ((0, utils_1.isIn)(type, constants_1.HYBRID_EXTENSION_TYPES)) {
|
|
212
|
+
return [path_1.default.posix.join(typeDir, '*', 'app.js'), path_1.default.posix.join(typeDir, '*', 'api.js')];
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
return path_1.default.posix.join(typeDir, '*', 'index.js');
|
|
216
|
+
}
|
|
190
217
|
});
|
|
191
218
|
this.watcher = chokidar_1.default.watch([path_1.default.resolve('package.json'), ...localExtensionPaths], {
|
|
192
219
|
ignoreInitial: true,
|
|
@@ -206,14 +233,12 @@ class ExtensionManager {
|
|
|
206
233
|
if (this.watcher) {
|
|
207
234
|
const toPackageExtensionPaths = (extensions) => extensions
|
|
208
235
|
.filter((extension) => !extension.local)
|
|
209
|
-
.flatMap((extension) => extension.type === '
|
|
210
|
-
?
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
]
|
|
216
|
-
: path_1.default.resolve(extension.path, extension.entrypoint));
|
|
236
|
+
.flatMap((extension) => (0, utils_1.isTypeIn)(extension, constants_1.HYBRID_EXTENSION_TYPES) || extension.type === 'bundle'
|
|
237
|
+
? [
|
|
238
|
+
path_1.default.resolve(extension.path, extension.entrypoint.app),
|
|
239
|
+
path_1.default.resolve(extension.path, extension.entrypoint.api),
|
|
240
|
+
]
|
|
241
|
+
: path_1.default.resolve(extension.path, extension.entrypoint));
|
|
217
242
|
const addedPackageExtensionPaths = toPackageExtensionPaths(added);
|
|
218
243
|
const removedPackageExtensionPaths = toPackageExtensionPaths(removed);
|
|
219
244
|
this.watcher.add(addedPackageExtensionPaths);
|
|
@@ -221,9 +246,10 @@ class ExtensionManager {
|
|
|
221
246
|
}
|
|
222
247
|
}
|
|
223
248
|
async getExtensions() {
|
|
224
|
-
const packageExtensions = await (0, node_1.getPackageExtensions)('.'
|
|
225
|
-
const
|
|
226
|
-
|
|
249
|
+
const packageExtensions = await (0, node_1.getPackageExtensions)('.');
|
|
250
|
+
const localPackageExtensions = await (0, node_1.resolvePackageExtensions)(env_1.default.EXTENSIONS_PATH);
|
|
251
|
+
const localExtensions = await (0, node_1.getLocalExtensions)(env_1.default.EXTENSIONS_PATH);
|
|
252
|
+
return [...packageExtensions, ...localPackageExtensions, ...localExtensions].filter((extension) => env_1.default.SERVE_APP || constants_1.APP_EXTENSION_TYPES.includes(extension.type) === false);
|
|
227
253
|
}
|
|
228
254
|
async generateExtensionBundle() {
|
|
229
255
|
const sharedDepsMapping = await this.getSharedDepsMapping(constants_1.APP_SHARED_DEPS);
|
package/dist/flows.js
CHANGED
|
@@ -64,6 +64,7 @@ exports.getFlowManager = getFlowManager;
|
|
|
64
64
|
const TRIGGER_KEY = '$trigger';
|
|
65
65
|
const ACCOUNTABILITY_KEY = '$accountability';
|
|
66
66
|
const LAST_KEY = '$last';
|
|
67
|
+
const ENV_KEY = '$env';
|
|
67
68
|
class FlowManager {
|
|
68
69
|
constructor() {
|
|
69
70
|
this.isLoaded = false;
|
|
@@ -265,6 +266,7 @@ class FlowManager {
|
|
|
265
266
|
[TRIGGER_KEY]: data,
|
|
266
267
|
[LAST_KEY]: data,
|
|
267
268
|
[ACCOUNTABILITY_KEY]: (_c = context === null || context === void 0 ? void 0 : context.accountability) !== null && _c !== void 0 ? _c : null,
|
|
269
|
+
[ENV_KEY]: (0, lodash_1.pick)(env_1.default, env_1.default.FLOWS_ENV_ALLOW_LIST ? (0, utils_1.toArray)(env_1.default.FLOWS_ENV_ALLOW_LIST) : []),
|
|
268
270
|
};
|
|
269
271
|
let nextOperation = flow.operation;
|
|
270
272
|
let lastOperationStatus = 'unknown';
|
|
@@ -5,10 +5,13 @@ const vm2_1 = require("vm2");
|
|
|
5
5
|
exports.default = (0, utils_1.defineOperationApi)({
|
|
6
6
|
id: 'exec',
|
|
7
7
|
handler: async ({ code }, { data, env }) => {
|
|
8
|
+
var _a;
|
|
8
9
|
const allowedModules = env.FLOWS_EXEC_ALLOWED_MODULES ? (0, utils_1.toArray)(env.FLOWS_EXEC_ALLOWED_MODULES) : [];
|
|
10
|
+
const allowedEnv = (_a = data.$env) !== null && _a !== void 0 ? _a : {};
|
|
9
11
|
const opts = {
|
|
10
12
|
eval: false,
|
|
11
13
|
wasm: false,
|
|
14
|
+
env: allowedEnv,
|
|
12
15
|
};
|
|
13
16
|
if (allowedModules.length > 0) {
|
|
14
17
|
opts.require = {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -30,7 +30,7 @@ exports.default = (0, utils_1.defineOperationApi)({
|
|
|
30
30
|
const sanitizedQueryObject = (0, sanitize_query_1.sanitizeQuery)(queryObject, customAccountability);
|
|
31
31
|
let result;
|
|
32
32
|
if (!key || (Array.isArray(key) && key.length === 0)) {
|
|
33
|
-
result = await itemsService.deleteByQuery(sanitizedQueryObject);
|
|
33
|
+
result = await itemsService.deleteByQuery(sanitizedQueryObject, { emitEvents: !!emitEvents });
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
36
|
const keys = (0, utils_1.toArray)(key);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -30,7 +30,7 @@ exports.default = (0, utils_1.defineOperationApi)({
|
|
|
30
30
|
const sanitizedQueryObject = (0, sanitize_query_1.sanitizeQuery)(queryObject, customAccountability);
|
|
31
31
|
let result;
|
|
32
32
|
if (!key || (Array.isArray(key) && key.length === 0)) {
|
|
33
|
-
result = await itemsService.readByQuery(sanitizedQueryObject);
|
|
33
|
+
result = await itemsService.readByQuery(sanitizedQueryObject, { emitEvents: !!emitEvents });
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
36
|
const keys = (0, utils_1.toArray)(key);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -7,8 +7,11 @@ exports.default = (0, utils_1.defineOperationApi)({
|
|
|
7
7
|
id: 'mail',
|
|
8
8
|
handler: async ({ body, to, type, subject }, { accountability, database, getSchema }) => {
|
|
9
9
|
const mailService = new services_1.MailService({ schema: await getSchema({ database }), accountability, knex: database });
|
|
10
|
+
// If 'body' is of type object/undefined (happens when body consists solely of a placeholder)
|
|
11
|
+
// convert it to JSON string
|
|
12
|
+
const safeBody = typeof body !== 'string' ? JSON.stringify(body) : body;
|
|
10
13
|
await mailService.send({
|
|
11
|
-
html: type === 'wysiwyg' ?
|
|
14
|
+
html: type === 'wysiwyg' ? safeBody : (0, md_1.md)(safeBody),
|
|
12
15
|
to,
|
|
13
16
|
subject,
|
|
14
17
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -265,6 +265,8 @@ class ExportService {
|
|
|
265
265
|
return string;
|
|
266
266
|
}
|
|
267
267
|
if (format === 'csv') {
|
|
268
|
+
if (input.length === 0)
|
|
269
|
+
return '';
|
|
268
270
|
const parser = new json2csv_1.Parser({
|
|
269
271
|
transforms: [json2csv_1.transforms.flatten({ separator: '.' })],
|
|
270
272
|
header: (options === null || options === void 0 ? void 0 : options.includeHeader) !== false,
|
package/dist/services/roles.js
CHANGED
|
@@ -35,7 +35,7 @@ class RolesService extends items_1.ItemsService {
|
|
|
35
35
|
userKeys = users.update.map((user) => user.id).filter((id) => id);
|
|
36
36
|
}
|
|
37
37
|
const usersThatWereInRoleBefore = (await this.knex.select('id').from('directus_users').where('role', '=', key)).map((user) => user.id);
|
|
38
|
-
const usersThatAreRemoved = usersThatWereInRoleBefore.filter((id) => userKeys.includes(id) === false);
|
|
38
|
+
const usersThatAreRemoved = usersThatWereInRoleBefore.filter((id) => Array.isArray(users) ? userKeys.includes(id) === false : users.delete.includes(id) === true);
|
|
39
39
|
const usersThatAreAdded = Array.isArray(users) ? users : users.create;
|
|
40
40
|
// If the role the users are moved to is an admin-role, and there's at least 1 (new) admin
|
|
41
41
|
// user, we don't have to check for other admin
|
package/dist/services/server.js
CHANGED
|
@@ -264,8 +264,11 @@ class ServerService {
|
|
|
264
264
|
const startTime = perf_hooks_1.performance.now();
|
|
265
265
|
try {
|
|
266
266
|
await disk.write(`health-${checkID}`, node_stream_1.Readable.from(['check']));
|
|
267
|
-
await disk.read(`health-${checkID}`);
|
|
268
|
-
|
|
267
|
+
const fileStream = await disk.read(`health-${checkID}`);
|
|
268
|
+
fileStream.on('data', async () => {
|
|
269
|
+
fileStream.destroy();
|
|
270
|
+
await disk.delete(`health-${checkID}`);
|
|
271
|
+
});
|
|
269
272
|
}
|
|
270
273
|
catch (err) {
|
|
271
274
|
checks[`storage:${location}:responseTime`][0].status = 'error';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Aggregate, Filter, Query, SchemaOverview } from '@directus/shared/types';
|
|
2
2
|
import { Knex } from 'knex';
|
|
3
3
|
import { AliasMap } from './get-column-path';
|
|
4
|
-
export declare const generateAlias: () => string;
|
|
4
|
+
export declare const generateAlias: (size?: number | undefined) => string;
|
|
5
5
|
/**
|
|
6
6
|
* Apply the Query to a given Knex query builder instance
|
|
7
7
|
*/
|
|
@@ -24,7 +24,7 @@ export declare function applySort(knex: Knex, schema: SchemaOverview, rootQuery:
|
|
|
24
24
|
}[];
|
|
25
25
|
hasMultiRelationalSort: boolean;
|
|
26
26
|
} | undefined;
|
|
27
|
-
export declare function applyLimit(rootQuery: Knex.QueryBuilder, limit: any): void;
|
|
27
|
+
export declare function applyLimit(knex: Knex, rootQuery: Knex.QueryBuilder, limit: any): void;
|
|
28
28
|
export declare function applyOffset(knex: Knex, rootQuery: Knex.QueryBuilder, offset: any): void;
|
|
29
29
|
export declare function applyFilter(knex: Knex, schema: SchemaOverview, rootQuery: Knex.QueryBuilder, rootFilter: Filter, collection: string, aliasMap: AliasMap): {
|
|
30
30
|
query: Knex.QueryBuilder<any, any>;
|
|
@@ -26,9 +26,7 @@ function applyQuery(knex, collection, dbQuery, query, schema, options) {
|
|
|
26
26
|
if (query.sort && !(options === null || options === void 0 ? void 0 : options.isInnerQuery) && !(options === null || options === void 0 ? void 0 : options.hasMultiRelationalSort)) {
|
|
27
27
|
applySort(knex, schema, dbQuery, query.sort, collection, aliasMap);
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
applyLimit(dbQuery, query.limit);
|
|
31
|
-
}
|
|
29
|
+
applyLimit(knex, dbQuery, query.limit);
|
|
32
30
|
if (query.offset) {
|
|
33
31
|
applyOffset(knex, dbQuery, query.offset);
|
|
34
32
|
}
|
|
@@ -175,9 +173,9 @@ function applySort(knex, schema, rootQuery, rootSort, collection, aliasMap, retu
|
|
|
175
173
|
rootQuery.orderBy(sortRecords);
|
|
176
174
|
}
|
|
177
175
|
exports.applySort = applySort;
|
|
178
|
-
function applyLimit(rootQuery, limit) {
|
|
179
|
-
if (typeof limit === 'number'
|
|
180
|
-
|
|
176
|
+
function applyLimit(knex, rootQuery, limit) {
|
|
177
|
+
if (typeof limit === 'number') {
|
|
178
|
+
(0, helpers_1.getHelpers)(knex).schema.applyLimit(rootQuery, limit);
|
|
181
179
|
}
|
|
182
180
|
}
|
|
183
181
|
exports.applyLimit = applyLimit;
|
|
@@ -4,18 +4,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getCacheKey = void 0;
|
|
7
|
-
const url_1 = __importDefault(require("url"));
|
|
8
7
|
const object_hash_1 = __importDefault(require("object-hash"));
|
|
9
|
-
const
|
|
8
|
+
const url_1 = __importDefault(require("url"));
|
|
9
|
+
const get_graphql_query_and_variables_1 = require("./get-graphql-query-and-variables");
|
|
10
10
|
function getCacheKey(req) {
|
|
11
|
-
var _a
|
|
11
|
+
var _a;
|
|
12
12
|
const path = url_1.default.parse(req.originalUrl).pathname;
|
|
13
|
-
const isGraphQl = path === null || path === void 0 ? void 0 : path.
|
|
14
|
-
const isGet = ((_a = req.method) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'get';
|
|
13
|
+
const isGraphQl = path === null || path === void 0 ? void 0 : path.startsWith('/graphql');
|
|
15
14
|
const info = {
|
|
16
|
-
user: ((
|
|
15
|
+
user: ((_a = req.accountability) === null || _a === void 0 ? void 0 : _a.user) || null,
|
|
17
16
|
path,
|
|
18
|
-
query: isGraphQl ? (0,
|
|
17
|
+
query: isGraphQl ? (0, get_graphql_query_and_variables_1.getGraphqlQueryAndVariables)(req) : req.sanitizedQuery,
|
|
19
18
|
};
|
|
20
19
|
const key = (0, object_hash_1.default)(info);
|
|
21
20
|
return key;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGraphqlQueryAndVariables = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
function getGraphqlQueryAndVariables(req) {
|
|
6
|
+
var _a;
|
|
7
|
+
const isGet = ((_a = req.method) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'get';
|
|
8
|
+
return (0, lodash_1.pick)(isGet ? req.query : req.body, ['query', 'variables']);
|
|
9
|
+
}
|
|
10
|
+
exports.getGraphqlQueryAndVariables = getGraphqlQueryAndVariables;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -15,19 +15,26 @@ const roles_1 = require("../services/roles");
|
|
|
15
15
|
const users_1 = require("../services/users");
|
|
16
16
|
const merge_permissions_1 = require("../utils/merge-permissions");
|
|
17
17
|
const merge_permissions_for_share_1 = require("./merge-permissions-for-share");
|
|
18
|
+
const logger_1 = __importDefault(require("../logger"));
|
|
18
19
|
async function getPermissions(accountability, schema) {
|
|
19
20
|
const database = (0, database_1.default)();
|
|
20
21
|
const { cache } = (0, cache_1.getCache)();
|
|
21
22
|
let permissions = [];
|
|
22
23
|
const { user, role, app, admin, share_scope } = accountability;
|
|
23
24
|
const cacheKey = `permissions-${(0, object_hash_1.default)({ user, role, app, admin, share_scope })}`;
|
|
24
|
-
if (env_1.default.CACHE_PERMISSIONS !== false) {
|
|
25
|
-
|
|
25
|
+
if (cache && env_1.default.CACHE_PERMISSIONS !== false) {
|
|
26
|
+
let cachedPermissions;
|
|
27
|
+
try {
|
|
28
|
+
cachedPermissions = await (0, cache_1.getSystemCache)(cacheKey);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
logger_1.default.warn(err, `[cache] Couldn't read key ${cacheKey}. ${err.message}`);
|
|
32
|
+
}
|
|
26
33
|
if (cachedPermissions) {
|
|
27
34
|
if (!cachedPermissions.containDynamicData) {
|
|
28
35
|
return processPermissions(accountability, cachedPermissions.permissions, {});
|
|
29
36
|
}
|
|
30
|
-
const cachedFilterContext = await (
|
|
37
|
+
const cachedFilterContext = await (0, cache_1.getCacheValue)(cache, `filterContext-${(0, object_hash_1.default)({ user, role, permissions: cachedPermissions.permissions })}`);
|
|
31
38
|
if (cachedFilterContext) {
|
|
32
39
|
return processPermissions(accountability, cachedPermissions.permissions, cachedFilterContext);
|
|
33
40
|
}
|
|
@@ -38,7 +45,7 @@ async function getPermissions(accountability, schema) {
|
|
|
38
45
|
? await getFilterContext(schema, accountability, requiredPermissionData)
|
|
39
46
|
: {};
|
|
40
47
|
if (containDynamicData && env_1.default.CACHE_ENABLED !== false) {
|
|
41
|
-
await (
|
|
48
|
+
await (0, cache_1.setCacheValue)(cache, `filterContext-${(0, object_hash_1.default)({ user, role, permissions })}`, filterContext);
|
|
42
49
|
}
|
|
43
50
|
return processPermissions(accountability, permissions, filterContext);
|
|
44
51
|
}
|
|
@@ -64,10 +71,10 @@ async function getPermissions(accountability, schema) {
|
|
|
64
71
|
const filterContext = containDynamicData
|
|
65
72
|
? await getFilterContext(schema, accountability, requiredPermissionData)
|
|
66
73
|
: {};
|
|
67
|
-
if (env_1.default.CACHE_PERMISSIONS !== false) {
|
|
74
|
+
if (cache && env_1.default.CACHE_PERMISSIONS !== false) {
|
|
68
75
|
await (0, cache_1.setSystemCache)(cacheKey, { permissions, containDynamicData });
|
|
69
76
|
if (containDynamicData && env_1.default.CACHE_ENABLED !== false) {
|
|
70
|
-
await (
|
|
77
|
+
await (0, cache_1.setCacheValue)(cache, `filterContext-${(0, object_hash_1.default)({ user, role, permissions })}`, filterContext);
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
80
|
return processPermissions(accountability, permissions, filterContext);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -15,9 +15,9 @@ const querySchema = joi_1.default.object({
|
|
|
15
15
|
group: joi_1.default.array().items(joi_1.default.string()),
|
|
16
16
|
sort: joi_1.default.array().items(joi_1.default.string()),
|
|
17
17
|
filter: joi_1.default.object({}).unknown(),
|
|
18
|
-
limit: joi_1.default.number(),
|
|
19
|
-
offset: joi_1.default.number(),
|
|
20
|
-
page: joi_1.default.number(),
|
|
18
|
+
limit: joi_1.default.number().integer().min(-1),
|
|
19
|
+
offset: joi_1.default.number().integer().min(0),
|
|
20
|
+
page: joi_1.default.number().integer().min(0),
|
|
21
21
|
meta: joi_1.default.array().items(joi_1.default.string().valid('total_count', 'filter_count')),
|
|
22
22
|
search: joi_1.default.string(),
|
|
23
23
|
export: joi_1.default.string().valid('json', 'csv', 'xml'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "directus",
|
|
3
|
-
"version": "9.22.
|
|
3
|
+
"version": "9.22.4",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"directus",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
],
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@authenio/samlify-node-xmllint": "2.0.0",
|
|
68
|
-
"@aws-sdk/client-ses": "3.
|
|
68
|
+
"@aws-sdk/client-ses": "3.236.0",
|
|
69
69
|
"@directus/format-title": "9.15.0",
|
|
70
70
|
"@godaddy/terminus": "4.11.2",
|
|
71
71
|
"@rollup/plugin-alias": "4.0.2",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"argon2": "0.30.2",
|
|
74
74
|
"async": "3.2.4",
|
|
75
75
|
"async-mutex": "0.4.0",
|
|
76
|
-
"axios": "1.1
|
|
76
|
+
"axios": "1.2.1",
|
|
77
77
|
"busboy": "1.6.0",
|
|
78
78
|
"bytes": "3.1.2",
|
|
79
79
|
"camelcase": "6.3.0",
|
|
@@ -90,15 +90,15 @@
|
|
|
90
90
|
"encodeurl": "1.0.2",
|
|
91
91
|
"eventemitter2": "6.4.9",
|
|
92
92
|
"execa": "5.1.1",
|
|
93
|
-
"exif-reader": "1.0
|
|
93
|
+
"exif-reader": "1.1.0",
|
|
94
94
|
"express": "4.18.2",
|
|
95
95
|
"fast-redact": "3.1.2",
|
|
96
96
|
"flat": "5.0.2",
|
|
97
|
-
"fs-extra": "
|
|
97
|
+
"fs-extra": "11.1.0",
|
|
98
98
|
"globby": "11.0.4",
|
|
99
99
|
"graphql": "16.6.0",
|
|
100
100
|
"graphql-compose": "9.0.10",
|
|
101
|
-
"helmet": "6.0.
|
|
101
|
+
"helmet": "6.0.1",
|
|
102
102
|
"icc": "2.0.0",
|
|
103
103
|
"inquirer": "8.2.4",
|
|
104
104
|
"ioredis": "5.2.4",
|
|
@@ -106,69 +106,69 @@
|
|
|
106
106
|
"js-yaml": "4.1.0",
|
|
107
107
|
"js2xmlparser": "5.0.0",
|
|
108
108
|
"json2csv": "5.0.7",
|
|
109
|
-
"jsonwebtoken": "
|
|
109
|
+
"jsonwebtoken": "9.0.0",
|
|
110
110
|
"keyv": "4.5.2",
|
|
111
111
|
"knex": "2.3.0",
|
|
112
112
|
"knex-schema-inspector": "3.0.0",
|
|
113
113
|
"ldapjs": "2.3.3",
|
|
114
|
-
"liquidjs": "
|
|
114
|
+
"liquidjs": "10.3.3",
|
|
115
115
|
"lodash": "4.17.21",
|
|
116
|
-
"marked": "4.2.
|
|
116
|
+
"marked": "4.2.4",
|
|
117
117
|
"micromustache": "8.0.3",
|
|
118
118
|
"mime-types": "2.1.35",
|
|
119
119
|
"ms": "2.1.3",
|
|
120
|
-
"nanoid": "3.
|
|
120
|
+
"nanoid": "3.3.4",
|
|
121
121
|
"node-cron": "3.0.2",
|
|
122
122
|
"node-machine-id": "1.1.12",
|
|
123
123
|
"nodemailer": "6.8.0",
|
|
124
124
|
"object-hash": "3.0.0",
|
|
125
|
-
"openapi3-ts": "3.1.
|
|
126
|
-
"openid-client": "5.3.
|
|
125
|
+
"openapi3-ts": "3.1.2",
|
|
126
|
+
"openid-client": "5.3.1",
|
|
127
127
|
"ora": "5.4.0",
|
|
128
128
|
"otplib": "12.0.1",
|
|
129
|
-
"pino": "8.
|
|
130
|
-
"pino-http": "8.
|
|
129
|
+
"pino": "8.8.0",
|
|
130
|
+
"pino-http": "8.3.0",
|
|
131
131
|
"pino-http-print": "3.1.0",
|
|
132
132
|
"pino-pretty": "9.1.1",
|
|
133
133
|
"qs": "6.11.0",
|
|
134
134
|
"rate-limiter-flexible": "2.4.1",
|
|
135
|
-
"rollup": "3.
|
|
135
|
+
"rollup": "3.7.5",
|
|
136
136
|
"samlify": "2.8.7",
|
|
137
|
-
"sanitize-html": "2.
|
|
138
|
-
"sharp": "0.31.
|
|
137
|
+
"sanitize-html": "2.8.1",
|
|
138
|
+
"sharp": "0.31.3",
|
|
139
139
|
"snappy": "7.2.2",
|
|
140
|
-
"stream-json": "1.7.
|
|
140
|
+
"stream-json": "1.7.5",
|
|
141
141
|
"strip-bom-stream": "4.0.0",
|
|
142
142
|
"tmp-promise": "3.0.3",
|
|
143
143
|
"update-check": "1.5.4",
|
|
144
144
|
"uuid": "9.0.0",
|
|
145
145
|
"uuid-validate": "0.0.3",
|
|
146
|
-
"vm2": "3.9.
|
|
146
|
+
"vm2": "3.9.13",
|
|
147
147
|
"wellknown": "0.5.0",
|
|
148
|
-
"@directus/app": "9.22.
|
|
149
|
-
"@directus/extensions-sdk": "9.22.
|
|
150
|
-
"@directus/schema": "9.22.
|
|
151
|
-
"@directus/shared": "9.22.
|
|
152
|
-
"@directus/specs": "9.22.
|
|
153
|
-
"@directus/storage": "9.22.
|
|
154
|
-
"@directus/storage-driver-azure": "9.22.
|
|
155
|
-
"@directus/storage-driver-cloudinary": "9.22.
|
|
156
|
-
"@directus/storage-driver-gcs": "9.22.
|
|
157
|
-
"@directus/storage-driver-local": "9.22.
|
|
158
|
-
"@directus/storage-driver-s3": "9.22.
|
|
148
|
+
"@directus/app": "9.22.3",
|
|
149
|
+
"@directus/extensions-sdk": "9.22.4",
|
|
150
|
+
"@directus/schema": "9.22.4",
|
|
151
|
+
"@directus/shared": "9.22.3",
|
|
152
|
+
"@directus/specs": "9.22.4",
|
|
153
|
+
"@directus/storage": "9.22.4",
|
|
154
|
+
"@directus/storage-driver-azure": "9.22.4",
|
|
155
|
+
"@directus/storage-driver-cloudinary": "9.22.4",
|
|
156
|
+
"@directus/storage-driver-gcs": "9.22.4",
|
|
157
|
+
"@directus/storage-driver-local": "9.22.4",
|
|
158
|
+
"@directus/storage-driver-s3": "9.22.4"
|
|
159
159
|
},
|
|
160
160
|
"devDependencies": {
|
|
161
|
-
"@ngneat/falso": "6.3.
|
|
162
|
-
"@types/async": "3.2.
|
|
161
|
+
"@ngneat/falso": "6.3.2",
|
|
162
|
+
"@types/async": "3.2.16",
|
|
163
163
|
"@types/busboy": "1.5.0",
|
|
164
164
|
"@types/bytes": "3.1.1",
|
|
165
165
|
"@types/cookie-parser": "1.4.3",
|
|
166
|
-
"@types/cors": "2.8.
|
|
167
|
-
"@types/deep-diff": "1.0.
|
|
166
|
+
"@types/cors": "2.8.13",
|
|
167
|
+
"@types/deep-diff": "1.0.2",
|
|
168
168
|
"@types/destroy": "1.0.0",
|
|
169
169
|
"@types/encodeurl": "1.0.0",
|
|
170
170
|
"@types/exif-reader": "1.0.0",
|
|
171
|
-
"@types/express": "4.17.
|
|
171
|
+
"@types/express": "4.17.15",
|
|
172
172
|
"@types/express-serve-static-core": "4.17.31",
|
|
173
173
|
"@types/fast-redact": "3.0.2",
|
|
174
174
|
"@types/flat": "5.0.2",
|
|
@@ -179,42 +179,40 @@
|
|
|
179
179
|
"@types/jsonwebtoken": "8.5.9",
|
|
180
180
|
"@types/keyv": "3.1.4",
|
|
181
181
|
"@types/ldapjs": "2.2.5",
|
|
182
|
-
"@types/lodash": "4.14.
|
|
183
|
-
"@types/marked": "4.0.
|
|
182
|
+
"@types/lodash": "4.14.191",
|
|
183
|
+
"@types/marked": "4.0.8",
|
|
184
184
|
"@types/mime-types": "2.1.1",
|
|
185
185
|
"@types/ms": "0.7.31",
|
|
186
|
-
"@types/node": "18.11.
|
|
186
|
+
"@types/node": "18.11.17",
|
|
187
187
|
"@types/node-cron": "3.0.6",
|
|
188
|
-
"@types/nodemailer": "6.4.
|
|
189
|
-
"@types/object-hash": "
|
|
190
|
-
"@types/pino": "7.0.4",
|
|
191
|
-
"@types/pino-http": "5.8.1",
|
|
188
|
+
"@types/nodemailer": "6.4.7",
|
|
189
|
+
"@types/object-hash": "3.0.2",
|
|
192
190
|
"@types/qs": "6.9.7",
|
|
193
|
-
"@types/sanitize-html": "2.
|
|
191
|
+
"@types/sanitize-html": "2.8.0",
|
|
194
192
|
"@types/sharp": "0.31.0",
|
|
195
193
|
"@types/stream-json": "1.7.2",
|
|
196
|
-
"@types/uuid": "
|
|
194
|
+
"@types/uuid": "9.0.0",
|
|
197
195
|
"@types/uuid-validate": "0.0.1",
|
|
198
196
|
"@types/wellknown": "0.5.4",
|
|
199
|
-
"@vitest/coverage-c8": "0.
|
|
197
|
+
"@vitest/coverage-c8": "0.26.2",
|
|
200
198
|
"copyfiles": "2.4.1",
|
|
201
199
|
"form-data": "4.0.0",
|
|
202
|
-
"knex-mock-client": "1.
|
|
200
|
+
"knex-mock-client": "1.11.0",
|
|
203
201
|
"ts-node": "10.9.1",
|
|
204
202
|
"ts-node-dev": "2.0.0",
|
|
205
|
-
"typescript": "4.9.
|
|
206
|
-
"vitest": "0.
|
|
203
|
+
"typescript": "4.9.4",
|
|
204
|
+
"vitest": "0.26.2"
|
|
207
205
|
},
|
|
208
206
|
"optionalDependencies": {
|
|
209
|
-
"@keyv/redis": "2.5.
|
|
210
|
-
"keyv-memcache": "1.
|
|
207
|
+
"@keyv/redis": "2.5.4",
|
|
208
|
+
"keyv-memcache": "1.3.3",
|
|
211
209
|
"memcached": "2.2.2",
|
|
212
210
|
"mysql": "2.18.1",
|
|
213
211
|
"nodemailer-mailgun-transport": "2.1.5",
|
|
214
212
|
"nodemailer-sendgrid": "1.0.3",
|
|
215
213
|
"pg": "8.8.0",
|
|
216
|
-
"sqlite3": "5.1.
|
|
217
|
-
"tedious": "15.1.
|
|
214
|
+
"sqlite3": "5.1.4",
|
|
215
|
+
"tedious": "15.1.2"
|
|
218
216
|
},
|
|
219
217
|
"engines": {
|
|
220
218
|
"node": ">=12.20.0"
|