directus 9.21.0 → 9.22.0
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/app.js +9 -5
- package/dist/app.test.d.ts +1 -0
- package/dist/auth/drivers/openid.js +3 -1
- package/dist/cli/commands/bootstrap/index.js +2 -2
- package/dist/cli/commands/schema/apply.js +0 -2
- package/dist/cli/commands/schema/snapshot.js +0 -2
- package/dist/cli/commands/security/secret.js +2 -2
- package/dist/cli/utils/create-env/env-stub.liquid +3 -3
- package/dist/cli/utils/create-env/index.js +5 -8
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -1
- package/dist/controllers/assets.js +9 -7
- package/dist/controllers/files.js +2 -1
- package/dist/controllers/utils.js +2 -2
- package/dist/database/helpers/fn/dialects/mssql.js +2 -1
- package/dist/database/helpers/fn/dialects/mysql.js +3 -2
- package/dist/database/helpers/fn/dialects/oracle.js +2 -1
- package/dist/database/helpers/fn/dialects/postgres.js +2 -1
- package/dist/database/helpers/fn/dialects/sqlite.js +2 -1
- package/dist/database/helpers/fn/types.d.ts +1 -0
- package/dist/database/helpers/fn/types.js +5 -4
- package/dist/database/helpers/index.d.ts +1 -1
- package/dist/database/helpers/schema/dialects/mssql.d.ts +6 -0
- package/dist/database/helpers/schema/dialects/mssql.js +14 -0
- package/dist/database/helpers/schema/dialects/mysql.d.ts +5 -0
- package/dist/database/helpers/schema/dialects/mysql.js +19 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/oracle.js +3 -0
- package/dist/database/helpers/schema/index.d.ts +2 -2
- package/dist/database/helpers/schema/index.js +4 -4
- package/dist/database/helpers/schema/types.d.ts +5 -0
- package/dist/database/helpers/schema/types.js +13 -0
- package/dist/database/index.d.ts +6 -0
- package/dist/database/index.js +20 -1
- package/dist/database/migrations/20211007A-update-presets.js +2 -2
- package/dist/database/migrations/run.js +7 -31
- package/dist/database/run-ast.js +132 -6
- package/dist/database/system-data/fields/index.js +2 -1
- package/dist/env.js +3 -2
- package/dist/exceptions/range-not-satisfiable.d.ts +1 -1
- package/dist/extensions.d.ts +7 -1
- package/dist/extensions.js +41 -15
- package/dist/logger.js +27 -1
- package/dist/middleware/schema.js +1 -1
- package/dist/operations/request/index.d.ts +1 -2
- package/dist/operations/request/index.js +2 -2
- package/dist/services/assets.d.ts +4 -3
- package/dist/services/assets.js +13 -11
- package/dist/services/authentication.js +4 -3
- package/dist/services/authorization.js +1 -1
- package/dist/services/collections.js +7 -7
- package/dist/services/fields.d.ts +3 -2
- package/dist/services/fields.js +40 -20
- package/dist/services/files.d.ts +4 -3
- package/dist/services/files.js +92 -68
- package/dist/services/flows.d.ts +0 -2
- package/dist/services/flows.js +0 -14
- package/dist/services/flows.test.d.ts +1 -0
- package/dist/services/graphql/index.d.ts +5 -1
- package/dist/services/graphql/index.js +29 -31
- package/dist/services/import-export.d.ts +4 -3
- package/dist/services/items.js +7 -1
- package/dist/services/meta.js +2 -2
- package/dist/services/operations.d.ts +0 -2
- package/dist/services/operations.js +0 -12
- package/dist/services/operations.test.d.ts +1 -0
- package/dist/services/permissions.d.ts +0 -5
- package/dist/services/permissions.js +0 -25
- package/dist/services/permissions.test.d.ts +1 -0
- package/dist/services/relations.d.ts +2 -2
- package/dist/services/relations.js +24 -16
- package/dist/services/roles.js +0 -3
- package/dist/services/roles.test.d.ts +1 -0
- package/dist/services/server.js +8 -6
- package/dist/services/shares.js +2 -2
- package/dist/services/specifications.js +12 -1
- package/dist/services/users.js +10 -4
- package/dist/services/webhooks.d.ts +0 -2
- package/dist/services/webhooks.js +0 -10
- package/dist/services/webhooks.test.d.ts +1 -0
- package/dist/storage/get-storage-driver.d.ts +3 -0
- package/dist/storage/get-storage-driver.js +20 -0
- package/dist/storage/get-storage-driver.test.d.ts +1 -0
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.js +20 -0
- package/dist/storage/index.test.d.ts +1 -0
- package/dist/storage/register-drivers.d.ts +2 -0
- package/dist/storage/register-drivers.js +22 -0
- package/dist/storage/register-drivers.test.d.ts +1 -0
- package/dist/storage/register-locations.d.ts +2 -0
- package/dist/storage/register-locations.js +17 -0
- package/dist/storage/register-locations.test.d.ts +1 -0
- package/dist/utils/apply-query.d.ts +27 -3
- package/dist/utils/apply-query.js +180 -127
- package/dist/utils/apply-snapshot.js +32 -13
- package/dist/utils/dynamic-import.d.ts +1 -0
- package/dist/utils/dynamic-import.js +7 -0
- package/dist/utils/get-collection-from-alias.d.ts +6 -0
- package/dist/utils/get-collection-from-alias.js +15 -0
- package/dist/utils/get-collection-from-alias.test.d.ts +1 -0
- package/dist/utils/get-column-path.d.ts +14 -8
- package/dist/utils/get-column-path.js +24 -7
- package/dist/utils/get-column.d.ts +8 -1
- package/dist/utils/get-column.js +10 -3
- package/dist/utils/get-config-from-env.js +3 -2
- package/dist/utils/get-default-value.d.ts +1 -1
- package/dist/utils/get-schema.d.ts +6 -2
- package/dist/utils/get-schema.js +1 -1
- package/dist/utils/get-snapshot.js +1 -1
- package/dist/utils/parse-image-metadata.d.ts +3 -0
- package/dist/utils/parse-image-metadata.js +73 -0
- package/dist/utils/track.js +2 -2
- package/dist/utils/validate-env.js +3 -2
- package/dist/webhooks.js +2 -2
- package/package.json +18 -22
- package/dist/storage.d.ts +0 -3
- package/dist/storage.js +0 -61
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
4
|
};
|
|
28
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
const format_title_1 = __importDefault(require("@directus/format-title"));
|
|
30
6
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
7
|
+
const lodash_1 = require("lodash");
|
|
31
8
|
const path_1 = __importDefault(require("path"));
|
|
32
9
|
const env_1 = __importDefault(require("../../env"));
|
|
33
10
|
const logger_1 = __importDefault(require("../../logger"));
|
|
34
|
-
const
|
|
11
|
+
const dynamic_import_1 = require("../../utils/dynamic-import");
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
const format_title_1 = __importDefault(require("@directus/format-title"));
|
|
35
14
|
async function run(database, direction, log = true) {
|
|
36
15
|
let migrationFiles = await fs_extra_1.default.readdir(__dirname);
|
|
37
16
|
const customMigrationsPath = path_1.default.resolve(env_1.default.EXTENSIONS_PATH, 'migrations');
|
|
@@ -65,7 +44,6 @@ async function run(database, direction, log = true) {
|
|
|
65
44
|
if (direction === 'latest')
|
|
66
45
|
await latest();
|
|
67
46
|
async function up() {
|
|
68
|
-
var _a;
|
|
69
47
|
const currentVersion = completedMigrations[completedMigrations.length - 1];
|
|
70
48
|
let nextVersion;
|
|
71
49
|
if (!currentVersion) {
|
|
@@ -79,7 +57,7 @@ async function run(database, direction, log = true) {
|
|
|
79
57
|
if (!nextVersion) {
|
|
80
58
|
throw Error('Nothing to upgrade');
|
|
81
59
|
}
|
|
82
|
-
const { up } = await (
|
|
60
|
+
const { up } = await (0, dynamic_import_1.dynamicImport)(nextVersion.file);
|
|
83
61
|
if (log) {
|
|
84
62
|
logger_1.default.info(`Applying ${nextVersion.name}...`);
|
|
85
63
|
}
|
|
@@ -87,7 +65,6 @@ async function run(database, direction, log = true) {
|
|
|
87
65
|
await database.insert({ version: nextVersion.version, name: nextVersion.name }).into('directus_migrations');
|
|
88
66
|
}
|
|
89
67
|
async function down() {
|
|
90
|
-
var _a;
|
|
91
68
|
const lastAppliedMigration = (0, lodash_1.orderBy)(completedMigrations, ['timestamp', 'version'], ['desc', 'desc'])[0];
|
|
92
69
|
if (!lastAppliedMigration) {
|
|
93
70
|
throw Error('Nothing to downgrade');
|
|
@@ -96,7 +73,7 @@ async function run(database, direction, log = true) {
|
|
|
96
73
|
if (!migration) {
|
|
97
74
|
throw new Error("Couldn't find migration");
|
|
98
75
|
}
|
|
99
|
-
const { down } = await (
|
|
76
|
+
const { down } = await (0, dynamic_import_1.dynamicImport)(migration.file);
|
|
100
77
|
if (log) {
|
|
101
78
|
logger_1.default.info(`Undoing ${migration.name}...`);
|
|
102
79
|
}
|
|
@@ -104,10 +81,9 @@ async function run(database, direction, log = true) {
|
|
|
104
81
|
await database('directus_migrations').delete().where({ version: migration.version });
|
|
105
82
|
}
|
|
106
83
|
async function latest() {
|
|
107
|
-
var _a;
|
|
108
84
|
for (const migration of migrations) {
|
|
109
85
|
if (migration.completed === false) {
|
|
110
|
-
const { up } = await (
|
|
86
|
+
const { up } = await (0, dynamic_import_1.dynamicImport)(migration.file);
|
|
111
87
|
if (log) {
|
|
112
88
|
logger_1.default.info(`Applying ${migration.name}...`);
|
|
113
89
|
}
|
package/dist/database/run-ast.js
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
@@ -10,7 +33,8 @@ const helpers_1 = require("../database/helpers");
|
|
|
10
33
|
const env_1 = __importDefault(require("../env"));
|
|
11
34
|
const payload_1 = require("../services/payload");
|
|
12
35
|
const apply_function_to_column_name_1 = require("../utils/apply-function-to-column-name");
|
|
13
|
-
const apply_query_1 =
|
|
36
|
+
const apply_query_1 = __importStar(require("../utils/apply-query"));
|
|
37
|
+
const get_collection_from_alias_1 = require("../utils/get-collection-from-alias");
|
|
14
38
|
const get_column_1 = require("../utils/get-column");
|
|
15
39
|
const strip_function_1 = require("../utils/strip-function");
|
|
16
40
|
/**
|
|
@@ -33,7 +57,7 @@ async function runAST(originalAST, schema, options) {
|
|
|
33
57
|
// Retrieve the database columns to select in the current AST
|
|
34
58
|
const { fieldNodes, primaryKeyField, nestedCollectionNodes } = await parseCurrentLevel(schema, collection, children, query);
|
|
35
59
|
// The actual knex query builder instance. This is a promise that resolves with the raw items from the db
|
|
36
|
-
const dbQuery = getDBQuery(schema, knex, collection, fieldNodes, query);
|
|
60
|
+
const dbQuery = await getDBQuery(schema, knex, collection, fieldNodes, query);
|
|
37
61
|
const rawItems = await dbQuery;
|
|
38
62
|
if (!rawItems)
|
|
39
63
|
return null;
|
|
@@ -152,17 +176,119 @@ function getColumnPreprocessor(knex, schema, table) {
|
|
|
152
176
|
return helpers.st.asText(table, field.field);
|
|
153
177
|
}
|
|
154
178
|
if (fieldNode.type === 'functionField') {
|
|
155
|
-
return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias, schema, fieldNode.query);
|
|
179
|
+
return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias, schema, { query: fieldNode.query });
|
|
156
180
|
}
|
|
157
181
|
return (0, get_column_1.getColumn)(knex, table, fieldNode.name, alias, schema);
|
|
158
182
|
};
|
|
159
183
|
}
|
|
160
|
-
function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
184
|
+
async function getDBQuery(schema, knex, table, fieldNodes, query) {
|
|
161
185
|
const preProcess = getColumnPreprocessor(knex, schema, table);
|
|
162
|
-
const dbQuery = knex.select(fieldNodes.map(preProcess)).from(table);
|
|
163
186
|
const queryCopy = (0, lodash_1.clone)(query);
|
|
187
|
+
const helpers = (0, helpers_1.getHelpers)(knex);
|
|
164
188
|
queryCopy.limit = typeof queryCopy.limit === 'number' ? queryCopy.limit : 100;
|
|
165
|
-
|
|
189
|
+
// Queries with aggregates and groupBy will not have duplicate result
|
|
190
|
+
if (queryCopy.aggregate || queryCopy.group) {
|
|
191
|
+
const flatQuery = knex.select(fieldNodes.map(preProcess)).from(table);
|
|
192
|
+
return await (0, apply_query_1.default)(knex, table, flatQuery, queryCopy, schema).query;
|
|
193
|
+
}
|
|
194
|
+
const primaryKey = schema.collections[table].primary;
|
|
195
|
+
const aliasMap = Object.create(null);
|
|
196
|
+
let dbQuery = knex.from(table);
|
|
197
|
+
let sortRecords;
|
|
198
|
+
const innerQuerySortRecords = [];
|
|
199
|
+
let hasMultiRelationalSort;
|
|
200
|
+
if (queryCopy.sort) {
|
|
201
|
+
const sortResult = (0, apply_query_1.applySort)(knex, schema, dbQuery, queryCopy.sort, table, aliasMap, true);
|
|
202
|
+
if (sortResult) {
|
|
203
|
+
sortRecords = sortResult.sortRecords;
|
|
204
|
+
hasMultiRelationalSort = sortResult.hasMultiRelationalSort;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const { hasMultiRelationalFilter } = await (0, apply_query_1.default)(knex, table, dbQuery, queryCopy, schema, {
|
|
208
|
+
aliasMap,
|
|
209
|
+
isInnerQuery: true,
|
|
210
|
+
hasMultiRelationalSort,
|
|
211
|
+
});
|
|
212
|
+
const needsInnerQuery = hasMultiRelationalSort || hasMultiRelationalFilter;
|
|
213
|
+
if (needsInnerQuery) {
|
|
214
|
+
dbQuery.select(`${table}.${primaryKey}`).distinct();
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
dbQuery.select(fieldNodes.map(preProcess));
|
|
218
|
+
}
|
|
219
|
+
if (sortRecords) {
|
|
220
|
+
if (needsInnerQuery) {
|
|
221
|
+
sortRecords.map((sortRecord) => {
|
|
222
|
+
const sortAlias = `sort_${(0, apply_query_1.generateAlias)()}`;
|
|
223
|
+
if (sortRecord.column.includes('.')) {
|
|
224
|
+
const [alias, field] = sortRecord.column.split('.');
|
|
225
|
+
dbQuery.select((0, get_column_1.getColumn)(knex, alias, field, sortAlias, schema, {
|
|
226
|
+
originalCollectionName: (0, get_collection_from_alias_1.getCollectionFromAlias)(alias, aliasMap),
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
dbQuery.select((0, get_column_1.getColumn)(knex, table, sortRecord.column, sortAlias, schema));
|
|
231
|
+
}
|
|
232
|
+
innerQuerySortRecords.push({ alias: sortAlias, order: sortRecord.order });
|
|
233
|
+
});
|
|
234
|
+
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
|
+
dbQuery = helpers.schema.applyMultiRelationalSort(knex, dbQuery, table, primaryKey, orderByString, orderByFields);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// Clears the order if any, eg: from MSSQL offset
|
|
261
|
+
dbQuery.clear('order');
|
|
262
|
+
sortRecords.map((sortRecord) => {
|
|
263
|
+
if (sortRecord.column.includes('.')) {
|
|
264
|
+
const [alias, field] = sortRecord.column.split('.');
|
|
265
|
+
sortRecord.column = (0, get_column_1.getColumn)(knex, alias, field, false, schema, {
|
|
266
|
+
originalCollectionName: (0, get_collection_from_alias_1.getCollectionFromAlias)(alias, aliasMap),
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
sortRecord.column = (0, get_column_1.getColumn)(knex, table, sortRecord.column, false, schema);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
dbQuery.orderBy(sortRecords);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (!needsInnerQuery)
|
|
277
|
+
return dbQuery;
|
|
278
|
+
const wrapperQuery = knex
|
|
279
|
+
.select(fieldNodes.map(preProcess))
|
|
280
|
+
.from(table)
|
|
281
|
+
.innerJoin(knex.raw('??', dbQuery.as('inner')), `${table}.${primaryKey}`, `inner.${primaryKey}`);
|
|
282
|
+
if (sortRecords && needsInnerQuery) {
|
|
283
|
+
innerQuerySortRecords.map((innerQuerySortRecord) => {
|
|
284
|
+
wrapperQuery.orderBy(`inner.${innerQuerySortRecord.alias}`, innerQuerySortRecord.order);
|
|
285
|
+
});
|
|
286
|
+
if (hasMultiRelationalSort) {
|
|
287
|
+
wrapperQuery.where('inner.directus_row_number', '=', 1);
|
|
288
|
+
(0, apply_query_1.applyLimit)(wrapperQuery, queryCopy.limit);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return wrapperQuery;
|
|
166
292
|
}
|
|
167
293
|
function applyParentFilters(schema, nestedCollectionNodes, parentItem) {
|
|
168
294
|
var _a;
|
|
@@ -7,9 +7,10 @@ exports.systemFieldRows = void 0;
|
|
|
7
7
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
8
|
const lodash_1 = require("lodash");
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const format_title_1 = __importDefault(require("@directus/format-title"));
|
|
11
10
|
const get_auth_providers_1 = require("../../../utils/get-auth-providers");
|
|
12
11
|
const require_yaml_1 = require("../../../utils/require-yaml");
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
const format_title_1 = __importDefault(require("@directus/format-title"));
|
|
13
14
|
const defaults = (0, require_yaml_1.requireYAML)(require.resolve('./_defaults.yaml'));
|
|
14
15
|
const fieldData = fs_extra_1.default.readdirSync(path_1.default.resolve(__dirname));
|
|
15
16
|
exports.systemFieldRows = [];
|
package/dist/env.js
CHANGED
|
@@ -14,7 +14,6 @@ const lodash_1 = require("lodash");
|
|
|
14
14
|
const path_1 = __importDefault(require("path"));
|
|
15
15
|
const require_yaml_1 = require("./utils/require-yaml");
|
|
16
16
|
const utils_1 = require("@directus/shared/utils");
|
|
17
|
-
const utils_2 = require("@directus/shared/utils");
|
|
18
17
|
// keeping this here for now to prevent a circular import to constants.ts
|
|
19
18
|
const allowedEnvironmentVars = [
|
|
20
19
|
// general
|
|
@@ -107,6 +106,7 @@ const allowedEnvironmentVars = [
|
|
|
107
106
|
'ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION',
|
|
108
107
|
'ASSETS_TRANSFORM_MAX_OPERATIONS',
|
|
109
108
|
'ASSETS_CONTENT_SECURITY_POLICY',
|
|
109
|
+
'ASSETS_INVALID_IMAGE_SENSITIVITY_LEVEL',
|
|
110
110
|
// auth
|
|
111
111
|
'AUTH_PROVIDERS',
|
|
112
112
|
'AUTH_DISABLE_DEFAULT',
|
|
@@ -237,6 +237,7 @@ const defaults = {
|
|
|
237
237
|
ASSETS_TRANSFORM_MAX_CONCURRENT: 1,
|
|
238
238
|
ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION: 6000,
|
|
239
239
|
ASSETS_TRANSFORM_MAX_OPERATIONS: 5,
|
|
240
|
+
ASSETS_INVALID_IMAGE_SENSITIVITY_LEVEL: 'warning',
|
|
240
241
|
IP_TRUST_PROXY: true,
|
|
241
242
|
IP_CUSTOM_HEADER: false,
|
|
242
243
|
IMPORT_IP_DENY_LIST: '0.0.0.0',
|
|
@@ -437,7 +438,7 @@ function processValues(env) {
|
|
|
437
438
|
}
|
|
438
439
|
function tryJSON(value) {
|
|
439
440
|
try {
|
|
440
|
-
return (0,
|
|
441
|
+
return (0, utils_1.parseJSON)(value);
|
|
441
442
|
}
|
|
442
443
|
catch {
|
|
443
444
|
return value;
|
package/dist/extensions.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Router } from 'express';
|
|
2
1
|
import { ExtensionType } from '@directus/shared/types';
|
|
2
|
+
import { Router } from 'express';
|
|
3
3
|
export declare function getExtensionManager(): ExtensionManager;
|
|
4
4
|
type Options = {
|
|
5
5
|
schedule: boolean;
|
|
@@ -14,6 +14,8 @@ declare class ExtensionManager {
|
|
|
14
14
|
private apiEmitter;
|
|
15
15
|
private hookEvents;
|
|
16
16
|
private endpointRouter;
|
|
17
|
+
private hookEmbedsHead;
|
|
18
|
+
private hookEmbedsBody;
|
|
17
19
|
private reloadQueue;
|
|
18
20
|
private watcher;
|
|
19
21
|
constructor();
|
|
@@ -22,6 +24,10 @@ declare class ExtensionManager {
|
|
|
22
24
|
getExtensionsList(type?: ExtensionType): string[];
|
|
23
25
|
getAppExtensions(): string | null;
|
|
24
26
|
getEndpointRouter(): Router;
|
|
27
|
+
getEmbeds(): {
|
|
28
|
+
head: string;
|
|
29
|
+
body: string;
|
|
30
|
+
};
|
|
25
31
|
private load;
|
|
26
32
|
private unload;
|
|
27
33
|
private initializeWatcher;
|
package/dist/extensions.js
CHANGED
|
@@ -27,31 +27,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.getExtensionManager = void 0;
|
|
30
|
+
const constants_1 = require("@directus/shared/constants");
|
|
31
|
+
const sharedExceptions = __importStar(require("@directus/shared/exceptions"));
|
|
32
|
+
const node_1 = require("@directus/shared/utils/node");
|
|
30
33
|
const express_1 = __importStar(require("express"));
|
|
34
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
31
35
|
const path_1 = __importDefault(require("path"));
|
|
32
|
-
const node_1 = require("@directus/shared/utils/node");
|
|
33
|
-
const constants_1 = require("@directus/shared/constants");
|
|
34
36
|
const database_1 = __importDefault(require("./database"));
|
|
35
37
|
const emitter_1 = __importStar(require("./emitter"));
|
|
36
38
|
const env_1 = __importDefault(require("./env"));
|
|
37
39
|
const exceptions = __importStar(require("./exceptions"));
|
|
38
|
-
const sharedExceptions = __importStar(require("@directus/shared/exceptions"));
|
|
39
40
|
const logger_1 = __importDefault(require("./logger"));
|
|
40
|
-
const
|
|
41
|
+
const dynamic_import_1 = require("./utils/dynamic-import");
|
|
41
42
|
const get_schema_1 = require("./utils/get-schema");
|
|
42
|
-
const
|
|
43
|
-
const node_cron_1 = require("node-cron");
|
|
44
|
-
const rollup_1 = require("rollup");
|
|
45
|
-
const plugin_virtual_1 = __importDefault(require("@rollup/plugin-virtual"));
|
|
43
|
+
const utils_1 = require("@directus/shared/utils");
|
|
46
44
|
const plugin_alias_1 = __importDefault(require("@rollup/plugin-alias"));
|
|
47
|
-
const
|
|
48
|
-
const get_module_default_1 = __importDefault(require("./utils/get-module-default"));
|
|
49
|
-
const lodash_1 = require("lodash");
|
|
45
|
+
const plugin_virtual_1 = __importDefault(require("@rollup/plugin-virtual"));
|
|
50
46
|
const chokidar_1 = __importDefault(require("chokidar"));
|
|
51
|
-
const utils_1 = require("@directus/shared/utils");
|
|
52
|
-
const flows_1 = require("./flows");
|
|
53
47
|
const globby_1 = __importDefault(require("globby"));
|
|
48
|
+
const lodash_1 = require("lodash");
|
|
49
|
+
const node_cron_1 = require("node-cron");
|
|
50
|
+
const rollup_1 = require("rollup");
|
|
51
|
+
const flows_1 = require("./flows");
|
|
52
|
+
const services = __importStar(require("./services"));
|
|
53
|
+
const get_module_default_1 = __importDefault(require("./utils/get-module-default"));
|
|
54
54
|
const job_queue_1 = require("./utils/job-queue");
|
|
55
|
+
const url_1 = require("./utils/url");
|
|
55
56
|
let extensionManager;
|
|
56
57
|
function getExtensionManager() {
|
|
57
58
|
if (extensionManager) {
|
|
@@ -72,6 +73,8 @@ class ExtensionManager {
|
|
|
72
73
|
this.appExtensions = null;
|
|
73
74
|
this.apiExtensions = [];
|
|
74
75
|
this.hookEvents = [];
|
|
76
|
+
this.hookEmbedsHead = [];
|
|
77
|
+
this.hookEmbedsBody = [];
|
|
75
78
|
this.watcher = null;
|
|
76
79
|
this.options = defaultOptions;
|
|
77
80
|
this.apiEmitter = new emitter_1.Emitter();
|
|
@@ -139,6 +142,17 @@ class ExtensionManager {
|
|
|
139
142
|
getEndpointRouter() {
|
|
140
143
|
return this.endpointRouter;
|
|
141
144
|
}
|
|
145
|
+
getEmbeds() {
|
|
146
|
+
return {
|
|
147
|
+
head: wrapEmbeds('Custom Embed Head', this.hookEmbedsHead),
|
|
148
|
+
body: wrapEmbeds('Custom Embed Body', this.hookEmbedsBody),
|
|
149
|
+
};
|
|
150
|
+
function wrapEmbeds(label, content) {
|
|
151
|
+
if (content.length === 0)
|
|
152
|
+
return '';
|
|
153
|
+
return `<!-- Start ${label} -->\n${content.join('\n')}\n<!-- End ${label} -->`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
142
156
|
async load() {
|
|
143
157
|
try {
|
|
144
158
|
await (0, node_1.ensureExtensionDirs)(env_1.default.EXTENSIONS_PATH, env_1.default.SERVE_APP ? constants_1.EXTENSION_TYPES : constants_1.API_OR_HYBRID_EXTENSION_TYPES);
|
|
@@ -252,12 +266,11 @@ class ExtensionManager {
|
|
|
252
266
|
return depsMapping;
|
|
253
267
|
}
|
|
254
268
|
async registerHooks() {
|
|
255
|
-
var _a;
|
|
256
269
|
const hooks = this.extensions.filter((extension) => extension.type === 'hook');
|
|
257
270
|
for (const hook of hooks) {
|
|
258
271
|
try {
|
|
259
272
|
const hookPath = path_1.default.resolve(hook.path, hook.entrypoint);
|
|
260
|
-
const hookInstance = await (
|
|
273
|
+
const hookInstance = await (0, dynamic_import_1.dynamicImport)(hookPath);
|
|
261
274
|
const config = (0, get_module_default_1.default)(hookInstance);
|
|
262
275
|
this.registerHook(config);
|
|
263
276
|
this.apiExtensions.push({ path: hookPath });
|
|
@@ -380,6 +393,19 @@ class ExtensionManager {
|
|
|
380
393
|
logger_1.default.warn(`Couldn't register cron hook. Provided cron is invalid: ${cron}`);
|
|
381
394
|
}
|
|
382
395
|
},
|
|
396
|
+
embed: (position, code) => {
|
|
397
|
+
const content = typeof code === 'function' ? code() : code;
|
|
398
|
+
if (content.trim().length === 0) {
|
|
399
|
+
logger_1.default.warn(`Couldn't register embed hook. Provided code is empty!`);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (position === 'head') {
|
|
403
|
+
this.hookEmbedsHead.push(content);
|
|
404
|
+
}
|
|
405
|
+
if (position === 'body') {
|
|
406
|
+
this.hookEmbedsBody.push(content);
|
|
407
|
+
}
|
|
408
|
+
},
|
|
383
409
|
};
|
|
384
410
|
register(registerFunctions, {
|
|
385
411
|
services,
|
package/dist/logger.js
CHANGED
|
@@ -41,13 +41,31 @@ const pinoOptions = {
|
|
|
41
41
|
censor: '--redact--',
|
|
42
42
|
},
|
|
43
43
|
};
|
|
44
|
+
const httpLoggerOptions = {
|
|
45
|
+
level: env_1.default.LOG_LEVEL || 'info',
|
|
46
|
+
redact: {
|
|
47
|
+
paths: ['req.headers.authorization', `req.cookies.${env_1.default.REFRESH_TOKEN_COOKIE_NAME}`],
|
|
48
|
+
censor: '--redact--',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
44
51
|
if (env_1.default.LOG_STYLE !== 'raw') {
|
|
45
52
|
pinoOptions.transport = {
|
|
53
|
+
target: 'pino-pretty',
|
|
54
|
+
options: {
|
|
55
|
+
ignore: 'hostname,pid',
|
|
56
|
+
sync: true,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
httpLoggerOptions.transport = {
|
|
46
60
|
target: 'pino-http-print',
|
|
47
61
|
options: {
|
|
48
62
|
all: true,
|
|
49
63
|
translateTime: 'SYS:HH:MM:ss',
|
|
50
64
|
relativeUrl: true,
|
|
65
|
+
prettyOptions: {
|
|
66
|
+
ignore: 'hostname,pid',
|
|
67
|
+
sync: true,
|
|
68
|
+
},
|
|
51
69
|
},
|
|
52
70
|
};
|
|
53
71
|
}
|
|
@@ -67,12 +85,20 @@ if (loggerEnvConfig.levels) {
|
|
|
67
85
|
};
|
|
68
86
|
},
|
|
69
87
|
};
|
|
88
|
+
httpLoggerOptions.formatters = {
|
|
89
|
+
level(label, number) {
|
|
90
|
+
return {
|
|
91
|
+
severity: customLogLevels[label] || 'info',
|
|
92
|
+
level: number,
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
};
|
|
70
96
|
delete loggerEnvConfig.levels;
|
|
71
97
|
}
|
|
72
98
|
const logger = (0, pino_1.default)((0, lodash_1.merge)(pinoOptions, loggerEnvConfig));
|
|
73
99
|
const httpLoggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_HTTP', ['LOGGER_HTTP_LOGGER']);
|
|
74
100
|
exports.expressLogger = (0, pino_http_1.default)({
|
|
75
|
-
logger,
|
|
101
|
+
logger: (0, pino_1.default)((0, lodash_1.merge)(httpLoggerOptions, loggerEnvConfig)),
|
|
76
102
|
...httpLoggerEnvConfig,
|
|
77
103
|
serializers: {
|
|
78
104
|
req(request) {
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
7
7
|
const get_schema_1 = require("../utils/get-schema");
|
|
8
8
|
const schema = (0, async_handler_1.default)(async (req, res, next) => {
|
|
9
|
-
req.schema = await (0, get_schema_1.getSchema)(
|
|
9
|
+
req.schema = await (0, get_schema_1.getSchema)();
|
|
10
10
|
return next();
|
|
11
11
|
});
|
|
12
12
|
exports.default = schema;
|
|
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const utils_1 = require("@directus/shared/utils");
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
7
|
const encodeurl_1 = __importDefault(require("encodeurl"));
|
|
9
8
|
exports.default = (0, utils_1.defineOperationApi)({
|
|
10
9
|
id: 'request',
|
|
11
10
|
handler: async ({ url, method, body, headers }) => {
|
|
12
11
|
var _a;
|
|
12
|
+
const axios = (await import('axios')).default;
|
|
13
13
|
const customHeaders = (_a = headers === null || headers === void 0 ? void 0 : headers.reduce((acc, { header, value }) => {
|
|
14
14
|
acc[header] = value;
|
|
15
15
|
return acc;
|
|
@@ -17,7 +17,7 @@ exports.default = (0, utils_1.defineOperationApi)({
|
|
|
17
17
|
if (!customHeaders['Content-Type'] && isValidJSON(body)) {
|
|
18
18
|
customHeaders['Content-Type'] = 'application/json';
|
|
19
19
|
}
|
|
20
|
-
const result = await (
|
|
20
|
+
const result = await axios({
|
|
21
21
|
url: (0, encodeurl_1.default)(url),
|
|
22
22
|
method,
|
|
23
23
|
data: body,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { Range,
|
|
2
|
+
import type { Range, Stat } from '@directus/storage';
|
|
3
3
|
import { Accountability } from '@directus/shared/types';
|
|
4
|
+
import type { Readable } from 'node:stream';
|
|
4
5
|
import { Knex } from 'knex';
|
|
5
6
|
import { AbstractServiceOptions, TransformationParams, TransformationPreset } from '../types';
|
|
6
7
|
import { AuthorizationService } from './authorization';
|
|
@@ -10,8 +11,8 @@ export declare class AssetsService {
|
|
|
10
11
|
authorizationService: AuthorizationService;
|
|
11
12
|
constructor(options: AbstractServiceOptions);
|
|
12
13
|
getAsset(id: string, transformation: TransformationParams | TransformationPreset, range?: Range): Promise<{
|
|
13
|
-
stream:
|
|
14
|
+
stream: Readable;
|
|
14
15
|
file: any;
|
|
15
|
-
stat:
|
|
16
|
+
stat: Stat;
|
|
16
17
|
}>;
|
|
17
18
|
}
|
package/dist/services/assets.js
CHANGED
|
@@ -37,7 +37,7 @@ const database_1 = __importDefault(require("../database"));
|
|
|
37
37
|
const env_1 = __importDefault(require("../env"));
|
|
38
38
|
const exceptions_1 = require("../exceptions");
|
|
39
39
|
const logger_1 = __importDefault(require("../logger"));
|
|
40
|
-
const storage_1 =
|
|
40
|
+
const storage_1 = require("../storage");
|
|
41
41
|
const TransformationUtils = __importStar(require("../utils/transformations"));
|
|
42
42
|
const authorization_1 = require("./authorization");
|
|
43
43
|
sharp_1.default.concurrency(1);
|
|
@@ -52,6 +52,7 @@ class AssetsService {
|
|
|
52
52
|
}
|
|
53
53
|
async getAsset(id, transformation, range) {
|
|
54
54
|
var _a;
|
|
55
|
+
const storage = await (0, storage_1.getStorage)();
|
|
55
56
|
const publicSettings = await this.knex
|
|
56
57
|
.select('project_logo', 'public_background', 'public_foreground')
|
|
57
58
|
.from('directus_settings')
|
|
@@ -71,7 +72,7 @@ class AssetsService {
|
|
|
71
72
|
const file = (await this.knex.select('*').from('directus_files').where({ id }).first());
|
|
72
73
|
if (!file)
|
|
73
74
|
throw new exceptions_1.ForbiddenException();
|
|
74
|
-
const
|
|
75
|
+
const exists = await storage.location(file.storage).exists(file.filename_disk);
|
|
75
76
|
if (!exists)
|
|
76
77
|
throw new exceptions_1.ForbiddenException();
|
|
77
78
|
if (range) {
|
|
@@ -113,15 +114,15 @@ class AssetsService {
|
|
|
113
114
|
const assetFilename = path_1.default.basename(file.filename_disk, path_1.default.extname(file.filename_disk)) +
|
|
114
115
|
getAssetSuffix(transforms) +
|
|
115
116
|
(maybeNewFormat ? `.${maybeNewFormat}` : path_1.default.extname(file.filename_disk));
|
|
116
|
-
const
|
|
117
|
+
const exists = await storage.location(file.storage).exists(assetFilename);
|
|
117
118
|
if (maybeNewFormat) {
|
|
118
119
|
file.type = (0, mime_types_1.contentType)(assetFilename) || null;
|
|
119
120
|
}
|
|
120
121
|
if (exists) {
|
|
121
122
|
return {
|
|
122
|
-
stream:
|
|
123
|
+
stream: await storage.location(file.storage).read(assetFilename, range),
|
|
123
124
|
file,
|
|
124
|
-
stat: await
|
|
125
|
+
stat: await storage.location(file.storage).stat(assetFilename),
|
|
125
126
|
};
|
|
126
127
|
}
|
|
127
128
|
// Check image size before transforming. Processing an image that's too large for the
|
|
@@ -135,10 +136,11 @@ class AssetsService {
|
|
|
135
136
|
throw new exceptions_1.IllegalAssetTransformation(`Image is too large to be transformed, or image size couldn't be determined.`);
|
|
136
137
|
}
|
|
137
138
|
return await semaphore.runExclusive(async () => {
|
|
138
|
-
const readStream =
|
|
139
|
+
const readStream = await storage.location(file.storage).read(file.filename_disk, range);
|
|
139
140
|
const transformer = (0, sharp_1.default)({
|
|
140
141
|
limitInputPixels: Math.pow(env_1.default.ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION, 2),
|
|
141
142
|
sequentialRead: true,
|
|
143
|
+
failOn: env_1.default.ASSETS_INVALID_IMAGE_SENSITIVITY_LEVEL,
|
|
142
144
|
});
|
|
143
145
|
if (transforms.find((transform) => transform[0] === 'rotate') === undefined)
|
|
144
146
|
transformer.rotate();
|
|
@@ -147,17 +149,17 @@ class AssetsService {
|
|
|
147
149
|
logger_1.default.error(e, `Couldn't transform file ${file.id}`);
|
|
148
150
|
readStream.unpipe(transformer);
|
|
149
151
|
});
|
|
150
|
-
await
|
|
152
|
+
await storage.location(file.storage).write(assetFilename, readStream.pipe(transformer), type);
|
|
151
153
|
return {
|
|
152
|
-
stream:
|
|
153
|
-
stat: await
|
|
154
|
+
stream: await storage.location(file.storage).read(assetFilename, range),
|
|
155
|
+
stat: await storage.location(file.storage).stat(assetFilename),
|
|
154
156
|
file,
|
|
155
157
|
};
|
|
156
158
|
});
|
|
157
159
|
}
|
|
158
160
|
else {
|
|
159
|
-
const readStream =
|
|
160
|
-
const stat = await
|
|
161
|
+
const readStream = await storage.location(file.storage).read(file.filename_disk, range);
|
|
162
|
+
const stat = await storage.location(file.storage).stat(file.filename_disk);
|
|
161
163
|
return { stream: readStream, file, stat };
|
|
162
164
|
}
|
|
163
165
|
}
|