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.
Files changed (113) hide show
  1. package/dist/app.js +12 -12
  2. package/dist/auth/drivers/ldap.js +22 -22
  3. package/dist/auth/drivers/local.js +7 -7
  4. package/dist/auth/drivers/oauth2.js +27 -25
  5. package/dist/auth/drivers/openid.js +32 -30
  6. package/dist/auth/drivers/saml.js +10 -10
  7. package/dist/auth.js +4 -3
  8. package/dist/cache.js +16 -11
  9. package/dist/cli/commands/bootstrap/index.js +5 -4
  10. package/dist/cli/utils/create-db-connection.js +1 -1
  11. package/dist/cli/utils/create-env/index.js +1 -1
  12. package/dist/constants.d.ts +1 -0
  13. package/dist/constants.js +6 -5
  14. package/dist/controllers/activity.js +9 -9
  15. package/dist/controllers/assets.js +19 -18
  16. package/dist/controllers/auth.js +13 -13
  17. package/dist/controllers/collections.js +10 -10
  18. package/dist/controllers/dashboards.js +9 -9
  19. package/dist/controllers/extensions.js +3 -3
  20. package/dist/controllers/fields.js +16 -16
  21. package/dist/controllers/files.js +16 -15
  22. package/dist/controllers/flows.js +11 -11
  23. package/dist/controllers/folders.js +9 -9
  24. package/dist/controllers/graphql.js +6 -6
  25. package/dist/controllers/items.js +17 -17
  26. package/dist/controllers/notifications.js +9 -9
  27. package/dist/controllers/operations.js +9 -9
  28. package/dist/controllers/panels.js +9 -9
  29. package/dist/controllers/permissions.js +9 -9
  30. package/dist/controllers/presets.js +9 -9
  31. package/dist/controllers/relations.js +10 -10
  32. package/dist/controllers/revisions.js +3 -3
  33. package/dist/controllers/roles.js +9 -9
  34. package/dist/controllers/schema.js +5 -5
  35. package/dist/controllers/server.js +7 -7
  36. package/dist/controllers/settings.js +2 -2
  37. package/dist/controllers/shares.js +13 -13
  38. package/dist/controllers/users.js +16 -16
  39. package/dist/controllers/utils.js +5 -5
  40. package/dist/controllers/webhooks.js +9 -9
  41. package/dist/database/helpers/fn/types.d.ts +0 -1
  42. package/dist/database/helpers/fn/types.js +0 -2
  43. package/dist/database/helpers/index.d.ts +3 -3
  44. package/dist/database/index.js +5 -5
  45. package/dist/database/migrations/20210805B-change-image-metadata-structure.js +15 -15
  46. package/dist/database/migrations/run.js +1 -1
  47. package/dist/database/run-ast.js +4 -4
  48. package/dist/database/system-data/collections/index.js +2 -2
  49. package/dist/database/system-data/fields/index.js +3 -3
  50. package/dist/env.js +1 -1
  51. package/dist/extensions.js +10 -10
  52. package/dist/flows.js +33 -31
  53. package/dist/logger.d.ts +1 -0
  54. package/dist/logger.js +32 -32
  55. package/dist/mailer.js +16 -16
  56. package/dist/messenger.js +4 -4
  57. package/dist/middleware/authenticate.js +1 -1
  58. package/dist/middleware/cache.js +11 -11
  59. package/dist/middleware/collection-exists.js +3 -3
  60. package/dist/middleware/cors.js +7 -7
  61. package/dist/middleware/error-handler.js +2 -2
  62. package/dist/middleware/extract-token.js +2 -2
  63. package/dist/middleware/graphql.js +12 -6
  64. package/dist/middleware/rate-limiter-global.js +5 -5
  65. package/dist/middleware/rate-limiter-ip.js +2 -2
  66. package/dist/middleware/respond.js +16 -16
  67. package/dist/middleware/sanitize-query.js +1 -1
  68. package/dist/operations/exec/index.js +2 -2
  69. package/dist/rate-limiter.js +1 -1
  70. package/dist/request/validate-ip.js +2 -2
  71. package/dist/server.js +4 -4
  72. package/dist/services/activity.js +14 -14
  73. package/dist/services/assets.js +6 -6
  74. package/dist/services/authentication.js +9 -9
  75. package/dist/services/collections.js +9 -9
  76. package/dist/services/fields.js +5 -5
  77. package/dist/services/files.js +12 -12
  78. package/dist/services/graphql/index.js +100 -98
  79. package/dist/services/import-export.js +6 -6
  80. package/dist/services/items.js +6 -6
  81. package/dist/services/mail/index.js +5 -5
  82. package/dist/services/meta.js +1 -0
  83. package/dist/services/notifications.js +4 -4
  84. package/dist/services/revisions.js +3 -3
  85. package/dist/services/roles.js +5 -5
  86. package/dist/services/server.js +27 -27
  87. package/dist/services/shares.js +9 -9
  88. package/dist/services/specifications.js +5 -3
  89. package/dist/services/users.d.ts +1 -5
  90. package/dist/services/users.js +24 -27
  91. package/dist/storage/register-locations.js +1 -1
  92. package/dist/utils/apply-query.js +2 -1
  93. package/dist/utils/dynamic-import.js +1 -1
  94. package/dist/utils/generate-hash.js +1 -1
  95. package/dist/utils/get-ast-from-query.js +1 -1
  96. package/dist/utils/get-auth-providers.js +1 -1
  97. package/dist/utils/get-cache-headers.js +3 -3
  98. package/dist/utils/get-collection-from-alias.js +1 -0
  99. package/dist/utils/get-default-value.js +1 -1
  100. package/dist/utils/get-ip-from-req.js +2 -2
  101. package/dist/utils/get-permissions.js +11 -11
  102. package/dist/utils/get-schema.js +2 -2
  103. package/dist/utils/is-url-allowed.js +5 -2
  104. package/dist/utils/sanitize-query.js +26 -26
  105. package/dist/utils/should-skip-cache.js +2 -2
  106. package/dist/utils/track.js +16 -16
  107. package/dist/utils/validate-query.js +1 -1
  108. package/dist/utils/validate-storage.js +8 -8
  109. package/dist/webhooks.js +2 -2
  110. package/package.json +13 -13
  111. package/dist/utils/redact-header-cookies.d.ts +0 -1
  112. package/dist/utils/redact-header-cookies.js +0 -11
  113. /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.payload = { data: items };
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.payload = { data: item };
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.payload = { data: records || null, meta };
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.pk, req.sanitizedQuery);
70
- res.locals.payload = { data: record || null };
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.payload = { data: result };
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.pk, req.body);
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.payload = { data: item || null };
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.pk);
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.sqlite | geometryHelpers.postgres | geometryHelpers.mysql | geometryHelpers.mssql | geometryHelpers.oracle | geometryHelpers.redshift;
10
- schema: schemaHelpers.sqlite | schemaHelpers.postgres | schemaHelpers.mysql | schemaHelpers.cockroachdb | schemaHelpers.mssql | schemaHelpers.oracle;
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.sqlite | fnHelpers.postgres | fnHelpers.mysql | fnHelpers.mssql | fnHelpers.oracle;
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>;
@@ -30,7 +30,7 @@ function getDatabase() {
30
30
  requiredEnvVars.push('DB_FILENAME');
31
31
  break;
32
32
  case 'oracledb':
33
- if (!env_1.default.DB_CONNECT_STRING) {
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.DB_TYPE || env_1.default.DB_TYPE === '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.EXTENSIONS_PATH, 'migrations');
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.DB_DATABASE });
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.DB_DATABASE })
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.ifd0) {
64
- newMetadata.exif.image = newMetadata.exif.ifd0;
65
- delete newMetadata.exif.ifd0;
63
+ if (newMetadata.exif['ifd0']) {
64
+ newMetadata.exif['image'] = newMetadata.exif['ifd0'];
65
+ delete newMetadata.exif['ifd0'];
66
66
  }
67
- if (newMetadata.exif.ifd1) {
68
- newMetadata.exif.thumbnail = newMetadata.exif.ifd1;
69
- delete newMetadata.exif.ifd1;
67
+ if (newMetadata.exif['ifd1']) {
68
+ newMetadata.exif['thumbnail'] = newMetadata.exif['ifd1'];
69
+ delete newMetadata.exif['ifd1'];
70
70
  }
71
- if (newMetadata.exif.interop) {
72
- newMetadata.exif.interoperability = newMetadata.exif.interop;
73
- delete newMetadata.exif.interop;
71
+ if (newMetadata.exif['interop']) {
72
+ newMetadata.exif['interoperability'] = newMetadata.exif['interop'];
73
+ delete newMetadata.exif['interop'];
74
74
  }
75
- if (newMetadata.exif.icc) {
76
- newMetadata.icc = newMetadata.exif.icc;
77
- delete newMetadata.exif.icc;
75
+ if (newMetadata.exif['icc']) {
76
+ newMetadata.icc = newMetadata.exif['icc'];
77
+ delete newMetadata.exif['icc'];
78
78
  }
79
- if (newMetadata.exif.iptc) {
80
- newMetadata.iptc = newMetadata.exif.iptc;
81
- delete newMetadata.exif.iptc;
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.EXTENSIONS_PATH, 'migrations');
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'));
@@ -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.RELATIONAL_BATCH_SIZE,
80
- offset: batchCount * env_1.default.RELATIONAL_BATCH_SIZE,
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.RELATIONAL_BATCH_SIZE) {
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.data.map((row) => {
8
- return (0, lodash_1.merge)({ system: true }, systemData.defaults, row);
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.fields.forEach((field, index) => {
21
+ systemFields['fields'].forEach((field, index) => {
22
22
  const systemField = (0, lodash_1.merge)({ system: true }, defaults, field, {
23
- collection: systemFields.table,
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.CONFIG_PATH || defaults.CONFIG_PATH);
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();
@@ -64,7 +64,7 @@ function getExtensionManager() {
64
64
  exports.getExtensionManager = getExtensionManager;
65
65
  const defaultOptions = {
66
66
  schedule: true,
67
- watch: env_1.default.EXTENSIONS_AUTO_RELOAD && env_1.default.NODE_ENV !== 'development',
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.EXTENSIONS_PATH, constants_1.NESTED_EXTENSION_TYPES);
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.SERVE_APP) {
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.SERVE_APP) {
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.EXTENSIONS_PATH), (0, utils_1.pluralize)(type));
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.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);
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.PUBLIC_URL).addPath('admin', 'assets', depName);
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.type === 'reload') {
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.scope)
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.collections).map((collection) => {
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.type === 'filter') {
153
+ if (flow.options['type'] === 'filter') {
154
154
  const handler = (payload, meta, context) => this.executeFlow(flow, { payload, ...meta }, {
155
- accountability: context.accountability,
156
- database: context.database,
157
- getSchema: context.schema ? () => context.schema : get_schema_1.getSchema,
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.type === 'action') {
165
+ else if (flow.options['type'] === 'action') {
166
166
  const handler = (meta, context) => this.executeFlow(flow, meta, {
167
- accountability: context.accountability,
167
+ accountability: context['accountability'],
168
168
  database: (0, database_1.default)(),
169
- getSchema: context.schema ? () => context.schema : get_schema_1.getSchema,
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.cron)) {
180
- const task = (0, node_cron_1.schedule)(flow.options.cron, async () => {
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.cron}`);
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.async) {
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.return = flow.options.return ?? '$last';
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.async) {
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.return = '$last';
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.database ?? (0, database_1.default)();
265
- const schema = context.schema ?? (await (0, get_schema_1.getSchema)({ database }));
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.FLOWS_ENV_ALLOW_LIST ? (0, utils_1.toArray)(env_1.default.FLOWS_ENV_ALLOW_LIST) : []),
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.type === 'filter' && lastOperationStatus === 'reject') {
316
+ if (flow.trigger === 'event' && flow.options['type'] === 'filter' && lastOperationStatus === 'reject') {
315
317
  throw keyedData[LAST_KEY];
316
318
  }
317
- if (flow.options.return === '$all') {
319
+ if (flow.options['return'] === '$all') {
318
320
  return keyedData;
319
321
  }
320
- else if (flow.options.return) {
321
- return (0, micromustache_1.get)(keyedData, flow.options.return);
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.LOG_LEVEL || 'info',
39
+ level: env_1.default['LOG_LEVEL'] || 'info',
40
40
  redact: {
41
- paths: ['req.headers.authorization', `req.cookies.${env_1.default.REFRESH_TOKEN_COOKIE_NAME}`],
42
- censor: '--redact--',
41
+ paths: ['req.headers.authorization', 'req.headers.cookie'],
42
+ censor: constants_1.REDACT_TEXT,
43
43
  },
44
44
  };
45
- const httpLoggerOptions = {
46
- level: env_1.default.LOG_LEVEL || 'info',
45
+ exports.httpLoggerOptions = {
46
+ level: env_1.default['LOG_LEVEL'] || 'info',
47
47
  redact: {
48
- paths: ['req.headers.authorization', `req.cookies.${env_1.default.REFRESH_TOKEN_COOKIE_NAME}`],
49
- censor: '--redact--',
48
+ paths: ['req.headers.authorization', 'req.headers.cookie'],
49
+ censor: constants_1.REDACT_TEXT,
50
50
  },
51
51
  };
52
- if (env_1.default.LOG_STYLE !== 'raw') {
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.levels) {
90
+ if (loggerEnvConfig['levels']) {
76
91
  const customLogLevels = {};
77
- for (const el of (0, utils_1.toArray)(loggerEnvConfig.levels)) {
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.levels;
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', '--redacted--');
131
+ url.searchParams.set('access_token', constants_1.REDACT_TEXT);
132
132
  }
133
133
  return url.pathname + url.search;
134
134
  }