directus 9.23.3 → 9.23.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/app.js +12 -12
- package/dist/auth/drivers/ldap.js +22 -22
- package/dist/auth/drivers/local.js +7 -7
- package/dist/auth/drivers/oauth2.js +27 -25
- package/dist/auth/drivers/openid.js +32 -30
- package/dist/auth/drivers/saml.js +10 -10
- package/dist/auth.js +4 -3
- package/dist/cache.js +16 -11
- package/dist/cli/commands/bootstrap/index.js +5 -4
- package/dist/cli/utils/create-db-connection.js +1 -1
- package/dist/cli/utils/create-env/index.js +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +6 -5
- package/dist/controllers/activity.js +9 -9
- package/dist/controllers/assets.js +19 -18
- package/dist/controllers/auth.js +13 -13
- package/dist/controllers/collections.js +10 -10
- package/dist/controllers/dashboards.js +9 -9
- package/dist/controllers/extensions.js +3 -3
- package/dist/controllers/fields.js +16 -16
- package/dist/controllers/files.js +16 -15
- package/dist/controllers/flows.js +11 -11
- package/dist/controllers/folders.js +9 -9
- package/dist/controllers/graphql.js +6 -6
- package/dist/controllers/items.js +17 -17
- package/dist/controllers/notifications.js +9 -9
- package/dist/controllers/operations.js +9 -9
- package/dist/controllers/panels.js +9 -9
- package/dist/controllers/permissions.js +9 -9
- package/dist/controllers/presets.js +9 -9
- package/dist/controllers/relations.js +10 -10
- package/dist/controllers/revisions.js +3 -3
- package/dist/controllers/roles.js +9 -9
- package/dist/controllers/schema.js +5 -5
- package/dist/controllers/server.js +7 -7
- package/dist/controllers/settings.js +2 -2
- package/dist/controllers/shares.js +13 -13
- package/dist/controllers/users.js +16 -16
- package/dist/controllers/utils.js +5 -5
- package/dist/controllers/webhooks.js +9 -9
- package/dist/database/helpers/fn/types.d.ts +0 -1
- package/dist/database/helpers/fn/types.js +0 -2
- package/dist/database/helpers/index.d.ts +3 -3
- package/dist/database/index.js +5 -5
- package/dist/database/migrations/20210805B-change-image-metadata-structure.js +15 -15
- package/dist/database/migrations/run.js +1 -1
- package/dist/database/run-ast.js +4 -4
- package/dist/database/system-data/collections/index.js +2 -2
- package/dist/database/system-data/fields/index.js +3 -3
- package/dist/env.js +1 -1
- package/dist/extensions.js +10 -10
- package/dist/flows.js +33 -31
- package/dist/logger.d.ts +1 -0
- package/dist/logger.js +32 -32
- package/dist/mailer.js +16 -16
- package/dist/messenger.js +4 -4
- package/dist/middleware/authenticate.js +1 -1
- package/dist/middleware/cache.js +11 -11
- package/dist/middleware/collection-exists.js +3 -3
- package/dist/middleware/cors.js +7 -7
- package/dist/middleware/error-handler.js +2 -2
- package/dist/middleware/extract-token.js +2 -2
- package/dist/middleware/graphql.js +12 -6
- package/dist/middleware/rate-limiter-global.js +5 -5
- package/dist/middleware/rate-limiter-ip.js +2 -2
- package/dist/middleware/respond.js +16 -16
- package/dist/middleware/sanitize-query.js +1 -1
- package/dist/operations/exec/index.js +2 -2
- package/dist/rate-limiter.js +1 -1
- package/dist/request/validate-ip.js +2 -2
- package/dist/server.js +4 -4
- package/dist/services/activity.js +14 -14
- package/dist/services/assets.js +6 -6
- package/dist/services/authentication.js +9 -9
- package/dist/services/collections.js +9 -9
- package/dist/services/fields.js +5 -5
- package/dist/services/files.js +12 -12
- package/dist/services/graphql/index.js +100 -98
- package/dist/services/import-export.js +6 -6
- package/dist/services/items.js +6 -6
- package/dist/services/mail/index.js +5 -5
- package/dist/services/meta.js +1 -0
- package/dist/services/notifications.js +4 -4
- package/dist/services/revisions.js +3 -3
- package/dist/services/roles.js +5 -5
- package/dist/services/server.js +27 -27
- package/dist/services/shares.js +9 -9
- package/dist/services/specifications.js +5 -3
- package/dist/services/users.d.ts +1 -5
- package/dist/services/users.js +24 -27
- package/dist/storage/register-locations.js +1 -1
- package/dist/utils/apply-query.js +2 -1
- package/dist/utils/dynamic-import.js +1 -1
- package/dist/utils/generate-hash.js +1 -1
- package/dist/utils/get-ast-from-query.js +1 -1
- package/dist/utils/get-auth-providers.js +1 -1
- package/dist/utils/get-cache-headers.js +3 -3
- package/dist/utils/get-collection-from-alias.js +1 -0
- package/dist/utils/get-default-value.js +1 -1
- package/dist/utils/get-ip-from-req.js +2 -2
- package/dist/utils/get-permissions.js +11 -11
- package/dist/utils/get-schema.js +2 -2
- package/dist/utils/is-url-allowed.js +5 -2
- package/dist/utils/sanitize-query.js +26 -26
- package/dist/utils/should-skip-cache.js +2 -2
- package/dist/utils/track.js +16 -16
- package/dist/utils/validate-query.js +1 -1
- package/dist/utils/validate-storage.js +8 -8
- package/dist/webhooks.js +2 -2
- package/package.json +13 -13
- package/dist/utils/redact-header-cookies.d.ts +0 -1
- package/dist/utils/redact-header-cookies.js +0 -11
- /package/dist/{utils/redact-header-cookies.test.d.ts → logger.test.d.ts} +0 -0
|
@@ -30,11 +30,11 @@ router.post('/', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
30
30
|
try {
|
|
31
31
|
if (Array.isArray(req.body)) {
|
|
32
32
|
const items = await service.readMany(savedKeys, req.sanitizedQuery);
|
|
33
|
-
res.locals
|
|
33
|
+
res.locals['payload'] = { data: items };
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
36
|
const item = await service.readOne(savedKeys[0], req.sanitizedQuery);
|
|
37
|
-
res.locals
|
|
37
|
+
res.locals['payload'] = { data: item };
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
catch (error) {
|
|
@@ -56,7 +56,7 @@ const readHandler = (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
56
56
|
});
|
|
57
57
|
const records = await service.readByQuery(req.sanitizedQuery);
|
|
58
58
|
const meta = await metaService.getMetaForQuery(req.collection, req.sanitizedQuery);
|
|
59
|
-
res.locals
|
|
59
|
+
res.locals['payload'] = { data: records || null, meta };
|
|
60
60
|
return next();
|
|
61
61
|
});
|
|
62
62
|
router.get('/', (0, validate_batch_1.validateBatch)('read'), readHandler, respond_1.respond);
|
|
@@ -66,8 +66,8 @@ router.get('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
66
66
|
accountability: req.accountability,
|
|
67
67
|
schema: req.schema,
|
|
68
68
|
});
|
|
69
|
-
const record = await service.readOne(req.params
|
|
70
|
-
res.locals
|
|
69
|
+
const record = await service.readOne(req.params['pk'], req.sanitizedQuery);
|
|
70
|
+
res.locals['payload'] = { data: record || null };
|
|
71
71
|
return next();
|
|
72
72
|
}), respond_1.respond);
|
|
73
73
|
router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handler_1.default)(async (req, res, next) => {
|
|
@@ -85,7 +85,7 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
|
|
|
85
85
|
}
|
|
86
86
|
try {
|
|
87
87
|
const result = await service.readMany(keys, req.sanitizedQuery);
|
|
88
|
-
res.locals
|
|
88
|
+
res.locals['payload'] = { data: result };
|
|
89
89
|
}
|
|
90
90
|
catch (error) {
|
|
91
91
|
if (error instanceof exceptions_1.ForbiddenException) {
|
|
@@ -100,10 +100,10 @@ router.patch('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
100
100
|
accountability: req.accountability,
|
|
101
101
|
schema: req.schema,
|
|
102
102
|
});
|
|
103
|
-
const primaryKey = await service.updateOne(req.params
|
|
103
|
+
const primaryKey = await service.updateOne(req.params['pk'], req.body);
|
|
104
104
|
try {
|
|
105
105
|
const item = await service.readOne(primaryKey, req.sanitizedQuery);
|
|
106
|
-
res.locals
|
|
106
|
+
res.locals['payload'] = { data: item || null };
|
|
107
107
|
}
|
|
108
108
|
catch (error) {
|
|
109
109
|
if (error instanceof exceptions_1.ForbiddenException) {
|
|
@@ -135,7 +135,7 @@ router.delete('/:pk', (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
135
135
|
accountability: req.accountability,
|
|
136
136
|
schema: req.schema,
|
|
137
137
|
});
|
|
138
|
-
await service.deleteOne(req.params
|
|
138
|
+
await service.deleteOne(req.params['pk']);
|
|
139
139
|
return next();
|
|
140
140
|
}), respond_1.respond);
|
|
141
141
|
exports.default = router;
|
|
@@ -7,7 +7,6 @@ export type FnHelperOptions = {
|
|
|
7
7
|
originalCollectionName: string | undefined;
|
|
8
8
|
};
|
|
9
9
|
export declare abstract class FnHelper extends DatabaseHelper {
|
|
10
|
-
protected knex: Knex;
|
|
11
10
|
protected schema: SchemaOverview;
|
|
12
11
|
constructor(knex: Knex, schema: SchemaOverview);
|
|
13
12
|
abstract year(table: string, column: string, options?: FnHelperOptions): Knex.Raw;
|
|
@@ -4,11 +4,9 @@ exports.FnHelper = void 0;
|
|
|
4
4
|
const apply_query_1 = require("../../../utils/apply-query");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
class FnHelper extends types_1.DatabaseHelper {
|
|
7
|
-
knex;
|
|
8
7
|
schema;
|
|
9
8
|
constructor(knex, schema) {
|
|
10
9
|
super(knex);
|
|
11
|
-
this.knex = knex;
|
|
12
10
|
this.schema = schema;
|
|
13
11
|
this.schema = schema;
|
|
14
12
|
}
|
|
@@ -6,8 +6,8 @@ import * as geometryHelpers from './geometry';
|
|
|
6
6
|
import * as schemaHelpers from './schema';
|
|
7
7
|
export declare function getHelpers(database: Knex): {
|
|
8
8
|
date: dateHelpers.postgres | dateHelpers.oracle | dateHelpers.mysql | dateHelpers.mssql | dateHelpers.sqlite;
|
|
9
|
-
st: geometryHelpers.
|
|
10
|
-
schema: schemaHelpers.
|
|
9
|
+
st: geometryHelpers.mysql | geometryHelpers.postgres | geometryHelpers.mssql | geometryHelpers.sqlite | geometryHelpers.oracle | geometryHelpers.redshift;
|
|
10
|
+
schema: schemaHelpers.mysql | schemaHelpers.cockroachdb | schemaHelpers.mssql | schemaHelpers.postgres | schemaHelpers.sqlite | schemaHelpers.oracle;
|
|
11
11
|
};
|
|
12
|
-
export declare function getFunctions(database: Knex, schema: SchemaOverview): fnHelpers.
|
|
12
|
+
export declare function getFunctions(database: Knex, schema: SchemaOverview): fnHelpers.mysql | fnHelpers.postgres | fnHelpers.mssql | fnHelpers.sqlite | fnHelpers.oracle;
|
|
13
13
|
export type Helpers = ReturnType<typeof getHelpers>;
|
package/dist/database/index.js
CHANGED
|
@@ -30,7 +30,7 @@ function getDatabase() {
|
|
|
30
30
|
requiredEnvVars.push('DB_FILENAME');
|
|
31
31
|
break;
|
|
32
32
|
case 'oracledb':
|
|
33
|
-
if (!env_1.default
|
|
33
|
+
if (!env_1.default['DB_CONNECT_STRING']) {
|
|
34
34
|
requiredEnvVars.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER', 'DB_PASSWORD');
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
@@ -47,7 +47,7 @@ function getDatabase() {
|
|
|
47
47
|
}
|
|
48
48
|
break;
|
|
49
49
|
case 'mssql':
|
|
50
|
-
if (!env_1.default
|
|
50
|
+
if (!env_1.default['DB_TYPE'] || env_1.default['DB_TYPE'] === 'default') {
|
|
51
51
|
requiredEnvVars.push('DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USER', 'DB_PASSWORD');
|
|
52
52
|
}
|
|
53
53
|
break;
|
|
@@ -211,7 +211,7 @@ async function validateMigrations() {
|
|
|
211
211
|
const database = getDatabase();
|
|
212
212
|
try {
|
|
213
213
|
let migrationFiles = await fs_extra_1.default.readdir(path_1.default.join(__dirname, 'migrations'));
|
|
214
|
-
const customMigrationsPath = path_1.default.resolve(env_1.default
|
|
214
|
+
const customMigrationsPath = path_1.default.resolve(env_1.default['EXTENSIONS_PATH'], 'migrations');
|
|
215
215
|
let customMigrationFiles = ((await fs_extra_1.default.pathExists(customMigrationsPath)) && (await fs_extra_1.default.readdir(customMigrationsPath))) || [];
|
|
216
216
|
migrationFiles = migrationFiles.filter((file) => file.startsWith('run') === false && file.endsWith('.d.ts') === false);
|
|
217
217
|
customMigrationFiles = customMigrationFiles.filter((file) => file.endsWith('.js'));
|
|
@@ -255,10 +255,10 @@ async function validateDatabaseCharset(database) {
|
|
|
255
255
|
const { collation } = await database.select(database.raw(`@@collation_database as collation`)).first();
|
|
256
256
|
const tables = await database('information_schema.tables')
|
|
257
257
|
.select({ name: 'TABLE_NAME', collation: 'TABLE_COLLATION' })
|
|
258
|
-
.where({ TABLE_SCHEMA: env_1.default
|
|
258
|
+
.where({ TABLE_SCHEMA: env_1.default['DB_DATABASE'] });
|
|
259
259
|
const columns = await database('information_schema.columns')
|
|
260
260
|
.select({ table_name: 'TABLE_NAME', name: 'COLUMN_NAME', collation: 'COLLATION_NAME' })
|
|
261
|
-
.where({ TABLE_SCHEMA: env_1.default
|
|
261
|
+
.where({ TABLE_SCHEMA: env_1.default['DB_DATABASE'] })
|
|
262
262
|
.whereNot({ COLLATION_NAME: collation });
|
|
263
263
|
let inconsistencies = '';
|
|
264
264
|
for (const table of tables) {
|
|
@@ -60,25 +60,25 @@ async function down(knex) {
|
|
|
60
60
|
if (Object.keys(prevMetadata).filter((key) => key !== 'icc' && key !== 'iptc').length > 0) {
|
|
61
61
|
// Put all data under 'exif' and rename/move keys afterwards
|
|
62
62
|
const newMetadata = { exif: prevMetadata };
|
|
63
|
-
if (newMetadata.exif
|
|
64
|
-
newMetadata.exif
|
|
65
|
-
delete newMetadata.exif
|
|
63
|
+
if (newMetadata.exif['ifd0']) {
|
|
64
|
+
newMetadata.exif['image'] = newMetadata.exif['ifd0'];
|
|
65
|
+
delete newMetadata.exif['ifd0'];
|
|
66
66
|
}
|
|
67
|
-
if (newMetadata.exif
|
|
68
|
-
newMetadata.exif
|
|
69
|
-
delete newMetadata.exif
|
|
67
|
+
if (newMetadata.exif['ifd1']) {
|
|
68
|
+
newMetadata.exif['thumbnail'] = newMetadata.exif['ifd1'];
|
|
69
|
+
delete newMetadata.exif['ifd1'];
|
|
70
70
|
}
|
|
71
|
-
if (newMetadata.exif
|
|
72
|
-
newMetadata.exif
|
|
73
|
-
delete newMetadata.exif
|
|
71
|
+
if (newMetadata.exif['interop']) {
|
|
72
|
+
newMetadata.exif['interoperability'] = newMetadata.exif['interop'];
|
|
73
|
+
delete newMetadata.exif['interop'];
|
|
74
74
|
}
|
|
75
|
-
if (newMetadata.exif
|
|
76
|
-
newMetadata.icc = newMetadata.exif
|
|
77
|
-
delete newMetadata.exif
|
|
75
|
+
if (newMetadata.exif['icc']) {
|
|
76
|
+
newMetadata.icc = newMetadata.exif['icc'];
|
|
77
|
+
delete newMetadata.exif['icc'];
|
|
78
78
|
}
|
|
79
|
-
if (newMetadata.exif
|
|
80
|
-
newMetadata.iptc = newMetadata.exif
|
|
81
|
-
delete newMetadata.exif
|
|
79
|
+
if (newMetadata.exif['iptc']) {
|
|
80
|
+
newMetadata.iptc = newMetadata.exif['iptc'];
|
|
81
|
+
delete newMetadata.exif['iptc'];
|
|
82
82
|
}
|
|
83
83
|
await knex('directus_files')
|
|
84
84
|
.update({ metadata: JSON.stringify(newMetadata) })
|
|
@@ -13,7 +13,7 @@ const dynamic_import_1 = require("../../utils/dynamic-import");
|
|
|
13
13
|
const format_title_1 = __importDefault(require("@directus/format-title"));
|
|
14
14
|
async function run(database, direction, log = true) {
|
|
15
15
|
let migrationFiles = await fs_extra_1.default.readdir(__dirname);
|
|
16
|
-
const customMigrationsPath = path_1.default.resolve(env_1.default
|
|
16
|
+
const customMigrationsPath = path_1.default.resolve(env_1.default['EXTENSIONS_PATH'], 'migrations');
|
|
17
17
|
let customMigrationFiles = ((await fs_extra_1.default.pathExists(customMigrationsPath)) && (await fs_extra_1.default.readdir(customMigrationsPath))) || [];
|
|
18
18
|
migrationFiles = migrationFiles.filter((file) => /^[0-9]+[A-Z]-[^.]+\.(?:js|ts)$/.test(file));
|
|
19
19
|
customMigrationFiles = customMigrationFiles.filter((file) => file.endsWith('.js'));
|
package/dist/database/run-ast.js
CHANGED
|
@@ -64,7 +64,7 @@ async function runAST(originalAST, schema, options) {
|
|
|
64
64
|
// Run the items through the special transforms
|
|
65
65
|
const payloadService = new payload_1.PayloadService(collection, { knex, schema });
|
|
66
66
|
let items = await payloadService.processValues('read', rawItems);
|
|
67
|
-
if (!items || items.length === 0)
|
|
67
|
+
if (!items || (Array.isArray(items) && items.length === 0))
|
|
68
68
|
return items;
|
|
69
69
|
// Apply the `_in` filters to the nested collection batches
|
|
70
70
|
const nestedNodes = applyParentFilters(schema, nestedCollectionNodes, items);
|
|
@@ -76,8 +76,8 @@ async function runAST(originalAST, schema, options) {
|
|
|
76
76
|
while (hasMore) {
|
|
77
77
|
const node = (0, lodash_1.merge)({}, nestedNode, {
|
|
78
78
|
query: {
|
|
79
|
-
limit: env_1.default
|
|
80
|
-
offset: batchCount * env_1.default
|
|
79
|
+
limit: env_1.default['RELATIONAL_BATCH_SIZE'],
|
|
80
|
+
offset: batchCount * env_1.default['RELATIONAL_BATCH_SIZE'],
|
|
81
81
|
page: null,
|
|
82
82
|
},
|
|
83
83
|
});
|
|
@@ -85,7 +85,7 @@ async function runAST(originalAST, schema, options) {
|
|
|
85
85
|
if (nestedItems) {
|
|
86
86
|
items = mergeWithParentItems(schema, nestedItems, items, nestedNode);
|
|
87
87
|
}
|
|
88
|
-
if (!nestedItems || nestedItems.length < env_1.default
|
|
88
|
+
if (!nestedItems || nestedItems.length < env_1.default['RELATIONAL_BATCH_SIZE']) {
|
|
89
89
|
hasMore = false;
|
|
90
90
|
}
|
|
91
91
|
batchCount++;
|
|
@@ -4,6 +4,6 @@ exports.systemCollectionRows = void 0;
|
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const require_yaml_1 = require("../../../utils/require-yaml");
|
|
6
6
|
const systemData = (0, require_yaml_1.requireYAML)(require.resolve('./collections.yaml'));
|
|
7
|
-
exports.systemCollectionRows = systemData
|
|
8
|
-
return (0, lodash_1.merge)({ system: true }, systemData
|
|
7
|
+
exports.systemCollectionRows = systemData['data'].map((row) => {
|
|
8
|
+
return (0, lodash_1.merge)({ system: true }, systemData['defaults'], row);
|
|
9
9
|
});
|
|
@@ -18,15 +18,15 @@ for (const filepath of fieldData) {
|
|
|
18
18
|
if (filepath.includes('_defaults') || filepath.includes('index'))
|
|
19
19
|
continue;
|
|
20
20
|
const systemFields = (0, require_yaml_1.requireYAML)(path_1.default.resolve(__dirname, filepath));
|
|
21
|
-
systemFields
|
|
21
|
+
systemFields['fields'].forEach((field, index) => {
|
|
22
22
|
const systemField = (0, lodash_1.merge)({ system: true }, defaults, field, {
|
|
23
|
-
collection: systemFields
|
|
23
|
+
collection: systemFields['table'],
|
|
24
24
|
sort: index + 1,
|
|
25
25
|
});
|
|
26
26
|
// Dynamically populate auth providers field
|
|
27
27
|
if (systemField.collection === 'directus_users' && systemField.field === 'provider') {
|
|
28
28
|
(0, get_auth_providers_1.getAuthProviders)().forEach(({ name }) => {
|
|
29
|
-
systemField.options?.choices?.push({
|
|
29
|
+
systemField.options?.['choices']?.push({
|
|
30
30
|
text: (0, format_title_1.default)(name),
|
|
31
31
|
value: name,
|
|
32
32
|
});
|
package/dist/env.js
CHANGED
|
@@ -308,7 +308,7 @@ function refreshEnv() {
|
|
|
308
308
|
}
|
|
309
309
|
exports.refreshEnv = refreshEnv;
|
|
310
310
|
function processConfiguration() {
|
|
311
|
-
const configPath = path_1.default.resolve(process.env
|
|
311
|
+
const configPath = path_1.default.resolve(process.env['CONFIG_PATH'] || defaults['CONFIG_PATH']);
|
|
312
312
|
if (fs_1.default.existsSync(configPath) === false)
|
|
313
313
|
return {};
|
|
314
314
|
const fileExt = path_1.default.extname(configPath).toLowerCase();
|
package/dist/extensions.js
CHANGED
|
@@ -64,7 +64,7 @@ function getExtensionManager() {
|
|
|
64
64
|
exports.getExtensionManager = getExtensionManager;
|
|
65
65
|
const defaultOptions = {
|
|
66
66
|
schedule: true,
|
|
67
|
-
watch: env_1.default
|
|
67
|
+
watch: env_1.default['EXTENSIONS_AUTO_RELOAD'] && env_1.default['NODE_ENV'] !== 'development',
|
|
68
68
|
};
|
|
69
69
|
class ExtensionManager {
|
|
70
70
|
isLoaded = false;
|
|
@@ -189,7 +189,7 @@ class ExtensionManager {
|
|
|
189
189
|
}
|
|
190
190
|
async load() {
|
|
191
191
|
try {
|
|
192
|
-
await (0, node_1.ensureExtensionDirs)(env_1.default
|
|
192
|
+
await (0, node_1.ensureExtensionDirs)(env_1.default['EXTENSIONS_PATH'], constants_1.NESTED_EXTENSION_TYPES);
|
|
193
193
|
this.extensions = await this.getExtensions();
|
|
194
194
|
}
|
|
195
195
|
catch (err) {
|
|
@@ -200,7 +200,7 @@ class ExtensionManager {
|
|
|
200
200
|
await this.registerEndpoints();
|
|
201
201
|
await this.registerOperations();
|
|
202
202
|
await this.registerBundles();
|
|
203
|
-
if (env_1.default
|
|
203
|
+
if (env_1.default['SERVE_APP']) {
|
|
204
204
|
this.appExtensions = await this.generateExtensionBundle();
|
|
205
205
|
}
|
|
206
206
|
this.isLoaded = true;
|
|
@@ -208,7 +208,7 @@ class ExtensionManager {
|
|
|
208
208
|
async unload() {
|
|
209
209
|
this.unregisterApiExtensions();
|
|
210
210
|
this.apiEmitter.offAll();
|
|
211
|
-
if (env_1.default
|
|
211
|
+
if (env_1.default['SERVE_APP']) {
|
|
212
212
|
this.appExtensions = null;
|
|
213
213
|
}
|
|
214
214
|
this.isLoaded = false;
|
|
@@ -217,7 +217,7 @@ class ExtensionManager {
|
|
|
217
217
|
if (!this.watcher) {
|
|
218
218
|
logger_1.default.info('Watching extensions for changes...');
|
|
219
219
|
const localExtensionPaths = constants_1.NESTED_EXTENSION_TYPES.flatMap((type) => {
|
|
220
|
-
const typeDir = path_1.default.posix.join((0, node_1.pathToRelativeUrl)(env_1.default
|
|
220
|
+
const typeDir = path_1.default.posix.join((0, node_1.pathToRelativeUrl)(env_1.default['EXTENSIONS_PATH']), (0, utils_1.pluralize)(type));
|
|
221
221
|
if ((0, utils_1.isIn)(type, constants_1.HYBRID_EXTENSION_TYPES)) {
|
|
222
222
|
return [path_1.default.posix.join(typeDir, '*', 'app.js'), path_1.default.posix.join(typeDir, '*', 'api.js')];
|
|
223
223
|
}
|
|
@@ -256,10 +256,10 @@ class ExtensionManager {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
async getExtensions() {
|
|
259
|
-
const packageExtensions = await (0, node_1.getPackageExtensions)(env_1.default
|
|
260
|
-
const localPackageExtensions = await (0, node_1.resolvePackageExtensions)(env_1.default
|
|
261
|
-
const localExtensions = await (0, node_1.getLocalExtensions)(env_1.default
|
|
262
|
-
return [...packageExtensions, ...localPackageExtensions, ...localExtensions].filter((extension) => env_1.default
|
|
259
|
+
const packageExtensions = await (0, node_1.getPackageExtensions)(env_1.default['PACKAGE_FILE_LOCATION']);
|
|
260
|
+
const localPackageExtensions = await (0, node_1.resolvePackageExtensions)(env_1.default['EXTENSIONS_PATH']);
|
|
261
|
+
const localExtensions = await (0, node_1.getLocalExtensions)(env_1.default['EXTENSIONS_PATH']);
|
|
262
|
+
return [...packageExtensions, ...localPackageExtensions, ...localExtensions].filter((extension) => env_1.default['SERVE_APP'] || constants_1.APP_EXTENSION_TYPES.includes(extension.type) === false);
|
|
263
263
|
}
|
|
264
264
|
async generateExtensionBundle() {
|
|
265
265
|
const sharedDepsMapping = await this.getSharedDepsMapping(constants_1.APP_SHARED_DEPS);
|
|
@@ -292,7 +292,7 @@ class ExtensionManager {
|
|
|
292
292
|
const depRegex = new RegExp(`${(0, lodash_1.escapeRegExp)(dep.replace(/\//g, '_'))}\\.[0-9a-f]{8}\\.entry\\.js`);
|
|
293
293
|
const depName = appDir.find((file) => depRegex.test(file));
|
|
294
294
|
if (depName) {
|
|
295
|
-
const depUrl = new url_1.Url(env_1.default
|
|
295
|
+
const depUrl = new url_1.Url(env_1.default['PUBLIC_URL']).addPath('admin', 'assets', depName);
|
|
296
296
|
depsMapping[dep] = depUrl.toString({ rootRelative: true });
|
|
297
297
|
}
|
|
298
298
|
else {
|
package/dist/flows.js
CHANGED
|
@@ -77,7 +77,7 @@ class FlowManager {
|
|
|
77
77
|
this.reloadQueue = new job_queue_1.JobQueue();
|
|
78
78
|
const messenger = (0, messenger_1.getMessenger)();
|
|
79
79
|
messenger.subscribe('flows', (event) => {
|
|
80
|
-
if (event
|
|
80
|
+
if (event['type'] === 'reload') {
|
|
81
81
|
this.reloadQueue.enqueue(async () => {
|
|
82
82
|
if (this.isLoaded) {
|
|
83
83
|
await this.unload();
|
|
@@ -132,13 +132,13 @@ class FlowManager {
|
|
|
132
132
|
for (const flow of flowTrees) {
|
|
133
133
|
if (flow.trigger === 'event') {
|
|
134
134
|
let events = [];
|
|
135
|
-
if (flow.options?.scope) {
|
|
136
|
-
events = (0, utils_1.toArray)(flow.options
|
|
135
|
+
if (flow.options?.['scope']) {
|
|
136
|
+
events = (0, utils_1.toArray)(flow.options['scope'])
|
|
137
137
|
.map((scope) => {
|
|
138
138
|
if (['items.create', 'items.update', 'items.delete'].includes(scope)) {
|
|
139
|
-
if (!flow.options?.collections)
|
|
139
|
+
if (!flow.options?.['collections'])
|
|
140
140
|
return [];
|
|
141
|
-
return (0, utils_1.toArray)(flow.options
|
|
141
|
+
return (0, utils_1.toArray)(flow.options['collections']).map((collection) => {
|
|
142
142
|
if (collection.startsWith('directus_')) {
|
|
143
143
|
const action = scope.split('.')[1];
|
|
144
144
|
return collection.substring(9) + '.' + action;
|
|
@@ -150,11 +150,11 @@ class FlowManager {
|
|
|
150
150
|
})
|
|
151
151
|
.flat();
|
|
152
152
|
}
|
|
153
|
-
if (flow.options
|
|
153
|
+
if (flow.options['type'] === 'filter') {
|
|
154
154
|
const handler = (payload, meta, context) => this.executeFlow(flow, { payload, ...meta }, {
|
|
155
|
-
accountability: context
|
|
156
|
-
database: context
|
|
157
|
-
getSchema: context
|
|
155
|
+
accountability: context['accountability'],
|
|
156
|
+
database: context['database'],
|
|
157
|
+
getSchema: context['schema'] ? () => context['schema'] : get_schema_1.getSchema,
|
|
158
158
|
});
|
|
159
159
|
events.forEach((event) => emitter_1.default.onFilter(event, handler));
|
|
160
160
|
this.triggerHandlers.push({
|
|
@@ -162,11 +162,11 @@ class FlowManager {
|
|
|
162
162
|
events: events.map((event) => ({ type: 'filter', name: event, handler })),
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
|
-
else if (flow.options
|
|
165
|
+
else if (flow.options['type'] === 'action') {
|
|
166
166
|
const handler = (meta, context) => this.executeFlow(flow, meta, {
|
|
167
|
-
accountability: context
|
|
167
|
+
accountability: context['accountability'],
|
|
168
168
|
database: (0, database_1.default)(),
|
|
169
|
-
getSchema: context
|
|
169
|
+
getSchema: context['schema'] ? () => context['schema'] : get_schema_1.getSchema,
|
|
170
170
|
});
|
|
171
171
|
events.forEach((event) => emitter_1.default.onAction(event, handler));
|
|
172
172
|
this.triggerHandlers.push({
|
|
@@ -176,8 +176,8 @@ class FlowManager {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
else if (flow.trigger === 'schedule') {
|
|
179
|
-
if ((0, node_cron_1.validate)(flow.options
|
|
180
|
-
const task = (0, node_cron_1.schedule)(flow.options
|
|
179
|
+
if ((0, node_cron_1.validate)(flow.options['cron'])) {
|
|
180
|
+
const task = (0, node_cron_1.schedule)(flow.options['cron'], async () => {
|
|
181
181
|
try {
|
|
182
182
|
await this.executeFlow(flow);
|
|
183
183
|
}
|
|
@@ -188,7 +188,7 @@ class FlowManager {
|
|
|
188
188
|
this.triggerHandlers.push({ id: flow.id, events: [{ type: flow.trigger, task }] });
|
|
189
189
|
}
|
|
190
190
|
else {
|
|
191
|
-
logger_1.default.warn(`Couldn't register cron trigger. Provided cron is invalid: ${flow.options
|
|
191
|
+
logger_1.default.warn(`Couldn't register cron trigger. Provided cron is invalid: ${flow.options['cron']}`);
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
else if (flow.trigger === 'operation') {
|
|
@@ -197,22 +197,23 @@ class FlowManager {
|
|
|
197
197
|
}
|
|
198
198
|
else if (flow.trigger === 'webhook') {
|
|
199
199
|
const handler = (data, context) => {
|
|
200
|
-
if (flow.options
|
|
200
|
+
if (flow.options['async']) {
|
|
201
201
|
this.executeFlow(flow, data, context);
|
|
202
|
+
return undefined;
|
|
202
203
|
}
|
|
203
204
|
else {
|
|
204
205
|
return this.executeFlow(flow, data, context);
|
|
205
206
|
}
|
|
206
207
|
};
|
|
207
|
-
const method = flow.options?.method ?? 'GET';
|
|
208
|
+
const method = flow.options?.['method'] ?? 'GET';
|
|
208
209
|
// Default return to $last for webhooks
|
|
209
|
-
flow.options
|
|
210
|
+
flow.options['return'] = flow.options['return'] ?? '$last';
|
|
210
211
|
this.webhookFlowHandlers[`${method}-${flow.id}`] = handler;
|
|
211
212
|
}
|
|
212
213
|
else if (flow.trigger === 'manual') {
|
|
213
214
|
const handler = (data, context) => {
|
|
214
|
-
const enabledCollections = flow.options?.collections ?? [];
|
|
215
|
-
const targetCollection = data?.body.collection;
|
|
215
|
+
const enabledCollections = flow.options?.['collections'] ?? [];
|
|
216
|
+
const targetCollection = data?.['body'].collection;
|
|
216
217
|
if (!targetCollection) {
|
|
217
218
|
logger_1.default.warn(`Manual trigger requires "collection" to be specified in the payload`);
|
|
218
219
|
throw new exceptions.ForbiddenException();
|
|
@@ -225,15 +226,16 @@ class FlowManager {
|
|
|
225
226
|
logger_1.default.warn(`Specified collection must be one of: ${enabledCollections.join(', ')}.`);
|
|
226
227
|
throw new exceptions.ForbiddenException();
|
|
227
228
|
}
|
|
228
|
-
if (flow.options
|
|
229
|
+
if (flow.options['async']) {
|
|
229
230
|
this.executeFlow(flow, data, context);
|
|
231
|
+
return undefined;
|
|
230
232
|
}
|
|
231
233
|
else {
|
|
232
234
|
return this.executeFlow(flow, data, context);
|
|
233
235
|
}
|
|
234
236
|
};
|
|
235
237
|
// Default return to $last for manual
|
|
236
|
-
flow.options
|
|
238
|
+
flow.options['return'] = '$last';
|
|
237
239
|
this.webhookFlowHandlers[`POST-${flow.id}`] = handler;
|
|
238
240
|
}
|
|
239
241
|
}
|
|
@@ -261,13 +263,13 @@ class FlowManager {
|
|
|
261
263
|
this.isLoaded = false;
|
|
262
264
|
}
|
|
263
265
|
async executeFlow(flow, data = null, context = {}) {
|
|
264
|
-
const database = context
|
|
265
|
-
const schema = context
|
|
266
|
+
const database = context['database'] ?? (0, database_1.default)();
|
|
267
|
+
const schema = context['schema'] ?? (await (0, get_schema_1.getSchema)({ database }));
|
|
266
268
|
const keyedData = {
|
|
267
269
|
[TRIGGER_KEY]: data,
|
|
268
270
|
[LAST_KEY]: data,
|
|
269
|
-
[ACCOUNTABILITY_KEY]: context?.accountability ?? null,
|
|
270
|
-
[ENV_KEY]: (0, lodash_1.pick)(env_1.default, env_1.default
|
|
271
|
+
[ACCOUNTABILITY_KEY]: context?.['accountability'] ?? null,
|
|
272
|
+
[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']) : []),
|
|
271
273
|
};
|
|
272
274
|
let nextOperation = flow.operation;
|
|
273
275
|
let lastOperationStatus = 'unknown';
|
|
@@ -285,7 +287,7 @@ class FlowManager {
|
|
|
285
287
|
knex: database,
|
|
286
288
|
schema: schema,
|
|
287
289
|
});
|
|
288
|
-
const accountability = context?.accountability;
|
|
290
|
+
const accountability = context?.['accountability'];
|
|
289
291
|
const activity = await activityService.createOne({
|
|
290
292
|
action: types_1.Action.RUN,
|
|
291
293
|
user: accountability?.user ?? null,
|
|
@@ -311,14 +313,14 @@ class FlowManager {
|
|
|
311
313
|
});
|
|
312
314
|
}
|
|
313
315
|
}
|
|
314
|
-
if (flow.trigger === 'event' && flow.options
|
|
316
|
+
if (flow.trigger === 'event' && flow.options['type'] === 'filter' && lastOperationStatus === 'reject') {
|
|
315
317
|
throw keyedData[LAST_KEY];
|
|
316
318
|
}
|
|
317
|
-
if (flow.options
|
|
319
|
+
if (flow.options['return'] === '$all') {
|
|
318
320
|
return keyedData;
|
|
319
321
|
}
|
|
320
|
-
else if (flow.options
|
|
321
|
-
return (0, micromustache_1.get)(keyedData, flow.options
|
|
322
|
+
else if (flow.options['return']) {
|
|
323
|
+
return (0, micromustache_1.get)(keyedData, flow.options['return']);
|
|
322
324
|
}
|
|
323
325
|
return undefined;
|
|
324
326
|
}
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="qs" />
|
|
2
2
|
import { LoggerOptions } from 'pino';
|
|
3
3
|
import type { RequestHandler } from 'express';
|
|
4
|
+
export declare const httpLoggerOptions: LoggerOptions;
|
|
4
5
|
declare const logger: import("pino").Logger<LoggerOptions & Record<string, any>>;
|
|
5
6
|
export declare const expressLogger: RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
|
|
6
7
|
export default logger;
|
package/dist/logger.js
CHANGED
|
@@ -26,30 +26,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.expressLogger = void 0;
|
|
29
|
+
exports.expressLogger = exports.httpLoggerOptions = void 0;
|
|
30
30
|
const utils_1 = require("@directus/shared/utils");
|
|
31
31
|
const lodash_1 = require("lodash");
|
|
32
32
|
const pino_1 = __importDefault(require("pino"));
|
|
33
33
|
const pino_http_1 = __importStar(require("pino-http"));
|
|
34
34
|
const url_1 = require("url");
|
|
35
35
|
const env_1 = __importDefault(require("./env"));
|
|
36
|
+
const constants_1 = require("./constants");
|
|
36
37
|
const get_config_from_env_1 = require("./utils/get-config-from-env");
|
|
37
|
-
const redact_header_cookies_1 = require("./utils/redact-header-cookies");
|
|
38
38
|
const pinoOptions = {
|
|
39
|
-
level: env_1.default
|
|
39
|
+
level: env_1.default['LOG_LEVEL'] || 'info',
|
|
40
40
|
redact: {
|
|
41
|
-
paths: ['req.headers.authorization',
|
|
42
|
-
censor:
|
|
41
|
+
paths: ['req.headers.authorization', 'req.headers.cookie'],
|
|
42
|
+
censor: constants_1.REDACT_TEXT,
|
|
43
43
|
},
|
|
44
44
|
};
|
|
45
|
-
|
|
46
|
-
level: env_1.default
|
|
45
|
+
exports.httpLoggerOptions = {
|
|
46
|
+
level: env_1.default['LOG_LEVEL'] || 'info',
|
|
47
47
|
redact: {
|
|
48
|
-
paths: ['req.headers.authorization',
|
|
49
|
-
censor:
|
|
48
|
+
paths: ['req.headers.authorization', 'req.headers.cookie'],
|
|
49
|
+
censor: constants_1.REDACT_TEXT,
|
|
50
50
|
},
|
|
51
51
|
};
|
|
52
|
-
if (env_1.default
|
|
52
|
+
if (env_1.default['LOG_STYLE'] !== 'raw') {
|
|
53
53
|
pinoOptions.transport = {
|
|
54
54
|
target: 'pino-pretty',
|
|
55
55
|
options: {
|
|
@@ -57,7 +57,7 @@ if (env_1.default.LOG_STYLE !== 'raw') {
|
|
|
57
57
|
sync: true,
|
|
58
58
|
},
|
|
59
59
|
};
|
|
60
|
-
httpLoggerOptions.transport = {
|
|
60
|
+
exports.httpLoggerOptions.transport = {
|
|
61
61
|
target: 'pino-http-print',
|
|
62
62
|
options: {
|
|
63
63
|
all: true,
|
|
@@ -70,11 +70,26 @@ if (env_1.default.LOG_STYLE !== 'raw') {
|
|
|
70
70
|
},
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
+
if (env_1.default['LOG_STYLE'] === 'raw') {
|
|
74
|
+
exports.httpLoggerOptions.redact = {
|
|
75
|
+
paths: ['req.headers.authorization', 'req.headers.cookie', 'res.headers'],
|
|
76
|
+
censor: (value, pathParts) => {
|
|
77
|
+
const path = pathParts.join('.');
|
|
78
|
+
if (path === 'res.headers') {
|
|
79
|
+
if ('set-cookie' in value) {
|
|
80
|
+
value['set-cookie'] = constants_1.REDACT_TEXT;
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
return constants_1.REDACT_TEXT;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
73
88
|
const loggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_', 'LOGGER_HTTP');
|
|
74
89
|
// Expose custom log levels into formatter function
|
|
75
|
-
if (loggerEnvConfig
|
|
90
|
+
if (loggerEnvConfig['levels']) {
|
|
76
91
|
const customLogLevels = {};
|
|
77
|
-
for (const el of (0, utils_1.toArray)(loggerEnvConfig
|
|
92
|
+
for (const el of (0, utils_1.toArray)(loggerEnvConfig['levels'])) {
|
|
78
93
|
const key_val = el.split(':');
|
|
79
94
|
customLogLevels[key_val[0].trim()] = key_val[1].trim();
|
|
80
95
|
}
|
|
@@ -86,7 +101,7 @@ if (loggerEnvConfig.levels) {
|
|
|
86
101
|
};
|
|
87
102
|
},
|
|
88
103
|
};
|
|
89
|
-
httpLoggerOptions.formatters = {
|
|
104
|
+
exports.httpLoggerOptions.formatters = {
|
|
90
105
|
level(label, number) {
|
|
91
106
|
return {
|
|
92
107
|
severity: customLogLevels[label] || 'info',
|
|
@@ -94,41 +109,26 @@ if (loggerEnvConfig.levels) {
|
|
|
94
109
|
};
|
|
95
110
|
},
|
|
96
111
|
};
|
|
97
|
-
delete loggerEnvConfig
|
|
112
|
+
delete loggerEnvConfig['levels'];
|
|
98
113
|
}
|
|
99
114
|
const logger = (0, pino_1.default)((0, lodash_1.merge)(pinoOptions, loggerEnvConfig));
|
|
100
115
|
const httpLoggerEnvConfig = (0, get_config_from_env_1.getConfigFromEnv)('LOGGER_HTTP', ['LOGGER_HTTP_LOGGER']);
|
|
101
116
|
exports.expressLogger = (0, pino_http_1.default)({
|
|
102
|
-
logger: (0, pino_1.default)((0, lodash_1.merge)(httpLoggerOptions, loggerEnvConfig)),
|
|
117
|
+
logger: (0, pino_1.default)((0, lodash_1.merge)(exports.httpLoggerOptions, loggerEnvConfig)),
|
|
103
118
|
...httpLoggerEnvConfig,
|
|
104
119
|
serializers: {
|
|
105
120
|
req(request) {
|
|
106
121
|
const output = pino_http_1.stdSerializers.req(request);
|
|
107
122
|
output.url = redactQuery(output.url);
|
|
108
|
-
if (output.headers?.cookie) {
|
|
109
|
-
output.headers.cookie = (0, redact_header_cookies_1.redactHeaderCookie)(output.headers.cookie, [
|
|
110
|
-
'access_token',
|
|
111
|
-
`${env_1.default.REFRESH_TOKEN_COOKIE_NAME}`,
|
|
112
|
-
]);
|
|
113
|
-
}
|
|
114
123
|
return output;
|
|
115
124
|
},
|
|
116
|
-
res(response) {
|
|
117
|
-
if (response.headers?.['set-cookie']) {
|
|
118
|
-
response.headers['set-cookie'] = (0, redact_header_cookies_1.redactHeaderCookie)(response.headers['set-cookie'], [
|
|
119
|
-
'access_token',
|
|
120
|
-
`${env_1.default.REFRESH_TOKEN_COOKIE_NAME}`,
|
|
121
|
-
]);
|
|
122
|
-
}
|
|
123
|
-
return response;
|
|
124
|
-
},
|
|
125
125
|
},
|
|
126
126
|
});
|
|
127
127
|
exports.default = logger;
|
|
128
128
|
function redactQuery(originalPath) {
|
|
129
129
|
const url = new url_1.URL(originalPath, 'http://example.com/');
|
|
130
130
|
if (url.searchParams.has('access_token')) {
|
|
131
|
-
url.searchParams.set('access_token',
|
|
131
|
+
url.searchParams.set('access_token', constants_1.REDACT_TEXT);
|
|
132
132
|
}
|
|
133
133
|
return url.pathname + url.search;
|
|
134
134
|
}
|