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.
Files changed (117) hide show
  1. package/dist/app.js +9 -5
  2. package/dist/app.test.d.ts +1 -0
  3. package/dist/auth/drivers/openid.js +3 -1
  4. package/dist/cli/commands/bootstrap/index.js +2 -2
  5. package/dist/cli/commands/schema/apply.js +0 -2
  6. package/dist/cli/commands/schema/snapshot.js +0 -2
  7. package/dist/cli/commands/security/secret.js +2 -2
  8. package/dist/cli/utils/create-env/env-stub.liquid +3 -3
  9. package/dist/cli/utils/create-env/index.js +5 -8
  10. package/dist/constants.d.ts +1 -0
  11. package/dist/constants.js +2 -1
  12. package/dist/controllers/assets.js +9 -7
  13. package/dist/controllers/files.js +2 -1
  14. package/dist/controllers/utils.js +2 -2
  15. package/dist/database/helpers/fn/dialects/mssql.js +2 -1
  16. package/dist/database/helpers/fn/dialects/mysql.js +3 -2
  17. package/dist/database/helpers/fn/dialects/oracle.js +2 -1
  18. package/dist/database/helpers/fn/dialects/postgres.js +2 -1
  19. package/dist/database/helpers/fn/dialects/sqlite.js +2 -1
  20. package/dist/database/helpers/fn/types.d.ts +1 -0
  21. package/dist/database/helpers/fn/types.js +5 -4
  22. package/dist/database/helpers/index.d.ts +1 -1
  23. package/dist/database/helpers/schema/dialects/mssql.d.ts +6 -0
  24. package/dist/database/helpers/schema/dialects/mssql.js +14 -0
  25. package/dist/database/helpers/schema/dialects/mysql.d.ts +5 -0
  26. package/dist/database/helpers/schema/dialects/mysql.js +19 -0
  27. package/dist/database/helpers/schema/dialects/oracle.d.ts +1 -0
  28. package/dist/database/helpers/schema/dialects/oracle.js +3 -0
  29. package/dist/database/helpers/schema/index.d.ts +2 -2
  30. package/dist/database/helpers/schema/index.js +4 -4
  31. package/dist/database/helpers/schema/types.d.ts +5 -0
  32. package/dist/database/helpers/schema/types.js +13 -0
  33. package/dist/database/index.d.ts +6 -0
  34. package/dist/database/index.js +20 -1
  35. package/dist/database/migrations/20211007A-update-presets.js +2 -2
  36. package/dist/database/migrations/run.js +7 -31
  37. package/dist/database/run-ast.js +132 -6
  38. package/dist/database/system-data/fields/index.js +2 -1
  39. package/dist/env.js +3 -2
  40. package/dist/exceptions/range-not-satisfiable.d.ts +1 -1
  41. package/dist/extensions.d.ts +7 -1
  42. package/dist/extensions.js +41 -15
  43. package/dist/logger.js +27 -1
  44. package/dist/middleware/schema.js +1 -1
  45. package/dist/operations/request/index.d.ts +1 -2
  46. package/dist/operations/request/index.js +2 -2
  47. package/dist/services/assets.d.ts +4 -3
  48. package/dist/services/assets.js +13 -11
  49. package/dist/services/authentication.js +4 -3
  50. package/dist/services/authorization.js +1 -1
  51. package/dist/services/collections.js +7 -7
  52. package/dist/services/fields.d.ts +3 -2
  53. package/dist/services/fields.js +40 -20
  54. package/dist/services/files.d.ts +4 -3
  55. package/dist/services/files.js +92 -68
  56. package/dist/services/flows.d.ts +0 -2
  57. package/dist/services/flows.js +0 -14
  58. package/dist/services/flows.test.d.ts +1 -0
  59. package/dist/services/graphql/index.d.ts +5 -1
  60. package/dist/services/graphql/index.js +29 -31
  61. package/dist/services/import-export.d.ts +4 -3
  62. package/dist/services/items.js +7 -1
  63. package/dist/services/meta.js +2 -2
  64. package/dist/services/operations.d.ts +0 -2
  65. package/dist/services/operations.js +0 -12
  66. package/dist/services/operations.test.d.ts +1 -0
  67. package/dist/services/permissions.d.ts +0 -5
  68. package/dist/services/permissions.js +0 -25
  69. package/dist/services/permissions.test.d.ts +1 -0
  70. package/dist/services/relations.d.ts +2 -2
  71. package/dist/services/relations.js +24 -16
  72. package/dist/services/roles.js +0 -3
  73. package/dist/services/roles.test.d.ts +1 -0
  74. package/dist/services/server.js +8 -6
  75. package/dist/services/shares.js +2 -2
  76. package/dist/services/specifications.js +12 -1
  77. package/dist/services/users.js +10 -4
  78. package/dist/services/webhooks.d.ts +0 -2
  79. package/dist/services/webhooks.js +0 -10
  80. package/dist/services/webhooks.test.d.ts +1 -0
  81. package/dist/storage/get-storage-driver.d.ts +3 -0
  82. package/dist/storage/get-storage-driver.js +20 -0
  83. package/dist/storage/get-storage-driver.test.d.ts +1 -0
  84. package/dist/storage/index.d.ts +5 -0
  85. package/dist/storage/index.js +20 -0
  86. package/dist/storage/index.test.d.ts +1 -0
  87. package/dist/storage/register-drivers.d.ts +2 -0
  88. package/dist/storage/register-drivers.js +22 -0
  89. package/dist/storage/register-drivers.test.d.ts +1 -0
  90. package/dist/storage/register-locations.d.ts +2 -0
  91. package/dist/storage/register-locations.js +17 -0
  92. package/dist/storage/register-locations.test.d.ts +1 -0
  93. package/dist/utils/apply-query.d.ts +27 -3
  94. package/dist/utils/apply-query.js +180 -127
  95. package/dist/utils/apply-snapshot.js +32 -13
  96. package/dist/utils/dynamic-import.d.ts +1 -0
  97. package/dist/utils/dynamic-import.js +7 -0
  98. package/dist/utils/get-collection-from-alias.d.ts +6 -0
  99. package/dist/utils/get-collection-from-alias.js +15 -0
  100. package/dist/utils/get-collection-from-alias.test.d.ts +1 -0
  101. package/dist/utils/get-column-path.d.ts +14 -8
  102. package/dist/utils/get-column-path.js +24 -7
  103. package/dist/utils/get-column.d.ts +8 -1
  104. package/dist/utils/get-column.js +10 -3
  105. package/dist/utils/get-config-from-env.js +3 -2
  106. package/dist/utils/get-default-value.d.ts +1 -1
  107. package/dist/utils/get-schema.d.ts +6 -2
  108. package/dist/utils/get-schema.js +1 -1
  109. package/dist/utils/get-snapshot.js +1 -1
  110. package/dist/utils/parse-image-metadata.d.ts +3 -0
  111. package/dist/utils/parse-image-metadata.js +73 -0
  112. package/dist/utils/track.js +2 -2
  113. package/dist/utils/validate-env.js +3 -2
  114. package/dist/webhooks.js +2 -2
  115. package/package.json +18 -22
  116. package/dist/storage.d.ts +0 -3
  117. package/dist/storage.js +0 -61
@@ -12,13 +12,19 @@ const get_schema_1 = require("./get-schema");
12
12
  const get_snapshot_1 = require("./get-snapshot");
13
13
  const get_snapshot_diff_1 = require("./get-snapshot-diff");
14
14
  const cache_1 = require("../cache");
15
+ const emitter_1 = __importDefault(require("../emitter"));
15
16
  async function applySnapshot(snapshot, options) {
16
17
  var _a, _b, _c, _d;
17
18
  const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
18
- const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database }));
19
+ const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database, bypassCache: true }));
19
20
  const { systemCache } = (0, cache_1.getCache)();
20
21
  const current = (_c = options === null || options === void 0 ? void 0 : options.current) !== null && _c !== void 0 ? _c : (await (0, get_snapshot_1.getSnapshot)({ database, schema }));
21
22
  const snapshotDiff = (_d = options === null || options === void 0 ? void 0 : options.diff) !== null && _d !== void 0 ? _d : (0, get_snapshot_diff_1.getSnapshotDiff)(current, snapshot);
23
+ const nestedActionEvents = [];
24
+ const mutationOptions = {
25
+ autoPurgeSystemCache: false,
26
+ bypassEmitAction: (params) => nestedActionEvents.push(params),
27
+ };
22
28
  await database.transaction(async (trx) => {
23
29
  const collectionsService = new services_1.CollectionsService({ knex: trx, schema });
24
30
  const getNestedCollectionsToCreate = (currentLevelCollection) => snapshotDiff.collections.filter(({ diff }) => { var _a, _b; return ((_b = (_a = diff[0].rhs) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.group) === currentLevelCollection; });
@@ -49,7 +55,7 @@ async function applySnapshot(snapshot, options) {
49
55
  await collectionsService.createOne({
50
56
  ...diff[0].rhs,
51
57
  fields,
52
- });
58
+ }, mutationOptions);
53
59
  }
54
60
  catch (err) {
55
61
  logger_1.default.error(`Failed to create collection "${collection}"`);
@@ -69,7 +75,7 @@ async function applySnapshot(snapshot, options) {
69
75
  const relationsService = new services_1.RelationsService({ knex: trx, schema });
70
76
  for (const relation of relations) {
71
77
  try {
72
- await relationsService.deleteOne(relation.collection, relation.field);
78
+ await relationsService.deleteOne(relation.collection, relation.field, mutationOptions);
73
79
  }
74
80
  catch (err) {
75
81
  logger_1.default.error(`Failed to delete collection "${collection}" due to relation "${relation.collection}.${relation.field}"`);
@@ -81,7 +87,7 @@ async function applySnapshot(snapshot, options) {
81
87
  }
82
88
  await deleteCollections(getNestedCollectionsToDelete(collection));
83
89
  try {
84
- await collectionsService.deleteOne(collection);
90
+ await collectionsService.deleteOne(collection, mutationOptions);
85
91
  }
86
92
  catch (err) {
87
93
  logger_1.default.error(`Failed to delete collection "${collection}"`);
@@ -130,7 +136,7 @@ async function applySnapshot(snapshot, options) {
130
136
  });
131
137
  if (newValues) {
132
138
  try {
133
- await collectionsService.updateOne(collection, newValues);
139
+ await collectionsService.updateOne(collection, newValues, mutationOptions);
134
140
  }
135
141
  catch (err) {
136
142
  logger_1.default.error(`Failed to update collection "${collection}"`);
@@ -139,11 +145,14 @@ async function applySnapshot(snapshot, options) {
139
145
  }
140
146
  }
141
147
  }
142
- const fieldsService = new services_1.FieldsService({ knex: trx, schema: await (0, get_schema_1.getSchema)({ database: trx }) });
148
+ const fieldsService = new services_1.FieldsService({
149
+ knex: trx,
150
+ schema: await (0, get_schema_1.getSchema)({ database: trx, bypassCache: true }),
151
+ });
143
152
  for (const { collection, field, diff } of snapshotDiff.fields) {
144
153
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N' && !isNestedMetaUpdate(diff === null || diff === void 0 ? void 0 : diff[0])) {
145
154
  try {
146
- await fieldsService.createField(collection, diff[0].rhs);
155
+ await fieldsService.createField(collection, diff[0].rhs, undefined, mutationOptions);
147
156
  }
148
157
  catch (err) {
149
158
  logger_1.default.error(`Failed to create field "${collection}.${field}"`);
@@ -158,7 +167,7 @@ async function applySnapshot(snapshot, options) {
158
167
  try {
159
168
  await fieldsService.updateField(collection, {
160
169
  ...newValues,
161
- });
170
+ }, mutationOptions);
162
171
  }
163
172
  catch (err) {
164
173
  logger_1.default.error(`Failed to update field "${collection}.${field}"`);
@@ -168,7 +177,7 @@ async function applySnapshot(snapshot, options) {
168
177
  }
169
178
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D' && !isNestedMetaUpdate(diff === null || diff === void 0 ? void 0 : diff[0])) {
170
179
  try {
171
- await fieldsService.deleteField(collection, field);
180
+ await fieldsService.deleteField(collection, field, mutationOptions);
172
181
  }
173
182
  catch (err) {
174
183
  logger_1.default.error(`Failed to delete field "${collection}.${field}"`);
@@ -179,7 +188,10 @@ async function applySnapshot(snapshot, options) {
179
188
  snapshotDiff.relations = snapshotDiff.relations.filter((relation) => (relation.collection === collection && relation.field === field) === false);
180
189
  }
181
190
  }
182
- const relationsService = new services_1.RelationsService({ knex: trx, schema: await (0, get_schema_1.getSchema)({ database: trx }) });
191
+ const relationsService = new services_1.RelationsService({
192
+ knex: trx,
193
+ schema: await (0, get_schema_1.getSchema)({ database: trx, bypassCache: true }),
194
+ });
183
195
  for (const { collection, field, diff } of snapshotDiff.relations) {
184
196
  const structure = {};
185
197
  for (const diffEdit of diff) {
@@ -187,7 +199,7 @@ async function applySnapshot(snapshot, options) {
187
199
  }
188
200
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'N') {
189
201
  try {
190
- await relationsService.createOne(diff[0].rhs);
202
+ await relationsService.createOne(diff[0].rhs, mutationOptions);
191
203
  }
192
204
  catch (err) {
193
205
  logger_1.default.error(`Failed to create relation "${collection}.${field}"`);
@@ -200,7 +212,7 @@ async function applySnapshot(snapshot, options) {
200
212
  });
201
213
  if (newValues) {
202
214
  try {
203
- await relationsService.updateOne(collection, field, newValues);
215
+ await relationsService.updateOne(collection, field, newValues, mutationOptions);
204
216
  }
205
217
  catch (err) {
206
218
  logger_1.default.error(`Failed to update relation "${collection}.${field}"`);
@@ -210,7 +222,7 @@ async function applySnapshot(snapshot, options) {
210
222
  }
211
223
  if ((diff === null || diff === void 0 ? void 0 : diff[0].kind) === 'D') {
212
224
  try {
213
- await relationsService.deleteOne(collection, field);
225
+ await relationsService.deleteOne(collection, field, mutationOptions);
214
226
  }
215
227
  catch (err) {
216
228
  logger_1.default.error(`Failed to delete relation "${collection}.${field}"`);
@@ -220,6 +232,13 @@ async function applySnapshot(snapshot, options) {
220
232
  }
221
233
  });
222
234
  await (systemCache === null || systemCache === void 0 ? void 0 : systemCache.clear());
235
+ if (nestedActionEvents.length > 0) {
236
+ const updatedSchema = await (0, get_schema_1.getSchema)({ database, bypassCache: true });
237
+ for (const nestedActionEvent of nestedActionEvents) {
238
+ nestedActionEvent.context.schema = updatedSchema;
239
+ emitter_1.default.emitAction(nestedActionEvent.event, nestedActionEvent.meta, nestedActionEvent.context);
240
+ }
241
+ }
223
242
  }
224
243
  exports.applySnapshot = applySnapshot;
225
244
  function isNestedMetaUpdate(diff) {
@@ -0,0 +1 @@
1
+ export declare const dynamicImport: (mod: string) => Promise<any>;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dynamicImport = void 0;
4
+ const dynamicImport = async (mod) => {
5
+ return process.env.VITEST ? await import(mod) : require(mod);
6
+ };
7
+ exports.dynamicImport = dynamicImport;
@@ -0,0 +1,6 @@
1
+ import { AliasMap } from './get-column-path';
2
+ /**
3
+ * Extract the collection of an alias within an aliasMap
4
+ * For example: 'ljnsv.name' -> 'authors'
5
+ */
6
+ export declare function getCollectionFromAlias(alias: string, aliasMap: AliasMap): string | undefined;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCollectionFromAlias = void 0;
4
+ /**
5
+ * Extract the collection of an alias within an aliasMap
6
+ * For example: 'ljnsv.name' -> 'authors'
7
+ */
8
+ function getCollectionFromAlias(alias, aliasMap) {
9
+ for (const aliasValue of Object.values(aliasMap)) {
10
+ if (aliasValue.alias === alias) {
11
+ return aliasValue.collection;
12
+ }
13
+ }
14
+ }
15
+ exports.getCollectionFromAlias = getCollectionFromAlias;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,20 +1,26 @@
1
- import { Relation } from '@directus/shared/types';
2
- type AliasMap = string | {
3
- [key: string]: AliasMap;
1
+ import { Relation, SchemaOverview } from '@directus/shared/types';
2
+ export type AliasMap = {
3
+ [key: string]: {
4
+ alias: string;
5
+ collection: string;
6
+ };
4
7
  };
5
8
  export type ColPathProps = {
6
9
  path: string[];
7
10
  collection: string;
8
11
  aliasMap: AliasMap;
9
12
  relations: Relation[];
13
+ schema?: SchemaOverview;
14
+ };
15
+ export type ColPathResult = {
16
+ columnPath: string;
17
+ targetCollection: string;
18
+ addNestedPkField?: string;
10
19
  };
11
20
  /**
12
21
  * Converts a Directus field list path to the correct SQL names based on the constructed alias map.
13
22
  * For example: ['author', 'role', 'name'] -> 'ljnsv.name'
14
23
  * Also returns the target collection of the column: 'directus_roles'
24
+ * If the last filter path is an alias field, a nested PK is appended to the path
15
25
  */
16
- export declare function getColumnPath({ path, collection, aliasMap, relations }: ColPathProps): {
17
- columnPath: string;
18
- targetCollection: string;
19
- };
20
- export {};
26
+ export declare function getColumnPath({ path, collection, aliasMap, relations, schema }: ColPathProps): ColPathResult;
@@ -3,15 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getColumnPath = void 0;
4
4
  const get_relation_info_1 = require("./get-relation-info");
5
5
  const exceptions_1 = require("../exceptions");
6
- const lodash_1 = require("lodash");
7
6
  /**
8
7
  * Converts a Directus field list path to the correct SQL names based on the constructed alias map.
9
8
  * For example: ['author', 'role', 'name'] -> 'ljnsv.name'
10
9
  * Also returns the target collection of the column: 'directus_roles'
10
+ * If the last filter path is an alias field, a nested PK is appended to the path
11
11
  */
12
- function getColumnPath({ path, collection, aliasMap, relations }) {
12
+ function getColumnPath({ path, collection, aliasMap, relations, schema }) {
13
13
  return followRelation(path);
14
- function followRelation(pathParts, parentCollection = collection, parentAlias) {
14
+ function followRelation(pathParts, parentCollection = collection, parentFields, addNestedPkField) {
15
+ var _a, _b, _c, _d;
15
16
  /**
16
17
  * For A2M fields, the path can contain an optional collection scope <field>:<scope>
17
18
  */
@@ -20,7 +21,7 @@ function getColumnPath({ path, collection, aliasMap, relations }) {
20
21
  if (!relation) {
21
22
  throw new exceptions_1.InvalidQueryException(`"${parentCollection}.${pathRoot}" is not a relational field`);
22
23
  }
23
- const alias = (0, lodash_1.get)(aliasMap, parentAlias ? [parentAlias, ...pathParts] : pathParts);
24
+ const alias = parentFields ? (_a = aliasMap[`${parentFields}.${pathParts[0]}`]) === null || _a === void 0 ? void 0 : _a.alias : (_b = aliasMap[pathParts[0]]) === null || _b === void 0 ? void 0 : _b.alias;
24
25
  const remainingParts = pathParts.slice(1);
25
26
  let parent;
26
27
  if (relationType === 'a2o') {
@@ -36,13 +37,29 @@ function getColumnPath({ path, collection, aliasMap, relations }) {
36
37
  else {
37
38
  parent = relation.collection;
38
39
  }
40
+ // Top level alias field
41
+ if (schema && !(((_c = remainingParts[0]) !== null && _c !== void 0 ? _c : parent).includes('(') && ((_d = remainingParts[0]) !== null && _d !== void 0 ? _d : parent).includes(')'))) {
42
+ if (remainingParts.length === 0) {
43
+ remainingParts.push(schema.collections[parent].primary);
44
+ addNestedPkField = schema.collections[parent].primary;
45
+ }
46
+ // Nested level alias field
47
+ else if (remainingParts.length === 1 && schema.collections[parent].fields[remainingParts[0]].type === 'alias') {
48
+ remainingParts.push(schema.collections[relation.related_collection].primary);
49
+ addNestedPkField = schema.collections[relation.related_collection].primary;
50
+ }
51
+ }
39
52
  if (remainingParts.length === 1) {
40
- return { columnPath: `${alias || parent}.${remainingParts[0]}`, targetCollection: parent };
53
+ return {
54
+ columnPath: `${alias || parent}.${remainingParts[0]}`,
55
+ targetCollection: parent,
56
+ addNestedPkField,
57
+ };
41
58
  }
42
59
  if (remainingParts.length) {
43
- return followRelation(remainingParts, parent, alias);
60
+ return followRelation(remainingParts, parent, `${parentFields ? parentFields + '.' : ''}${pathParts[0]}`, addNestedPkField);
44
61
  }
45
- return { columnPath: '', targetCollection: '' };
62
+ return { columnPath: '', targetCollection: '', addNestedPkField };
46
63
  }
47
64
  }
48
65
  exports.getColumnPath = getColumnPath;
@@ -1,5 +1,9 @@
1
1
  import { Query, SchemaOverview } from '@directus/shared/types';
2
2
  import { Knex } from 'knex';
3
+ type GetColumnOptions = {
4
+ query?: Query;
5
+ originalCollectionName?: string;
6
+ };
3
7
  /**
4
8
  * Return column prefixed by table. If column includes functions (like `year(date_created)`), the
5
9
  * column is replaced with the appropriate SQL
@@ -8,6 +12,9 @@ import { Knex } from 'knex';
8
12
  * @param table Collection or alias in which column resides
9
13
  * @param column name of the column
10
14
  * @param alias Whether or not to add a SQL AS statement
15
+ * @param schema For retrieval of the column type
16
+ * @param options Optional parameters
11
17
  * @returns Knex raw instance
12
18
  */
13
- export declare function getColumn(knex: Knex, table: string, column: string, alias: string | false | undefined, schema: SchemaOverview, query?: Query): Knex.Raw;
19
+ export declare function getColumn(knex: Knex, table: string, column: string, alias: string | false | undefined, schema: SchemaOverview, options?: GetColumnOptions): Knex.Raw;
20
+ export {};
@@ -14,21 +14,28 @@ const apply_function_to_column_name_1 = require("./apply-function-to-column-name
14
14
  * @param table Collection or alias in which column resides
15
15
  * @param column name of the column
16
16
  * @param alias Whether or not to add a SQL AS statement
17
+ * @param schema For retrieval of the column type
18
+ * @param options Optional parameters
17
19
  * @returns Knex raw instance
18
20
  */
19
- function getColumn(knex, table, column, alias = (0, apply_function_to_column_name_1.applyFunctionToColumnName)(column), schema, query) {
21
+ function getColumn(knex, table, column, alias = (0, apply_function_to_column_name_1.applyFunctionToColumnName)(column), schema, options) {
20
22
  var _a, _b, _c, _d;
21
23
  const fn = (0, helpers_1.getFunctions)(knex, schema);
22
24
  if (column.includes('(') && column.includes(')')) {
23
25
  const functionName = column.split('(')[0];
24
26
  const columnName = column.match(constants_1.REGEX_BETWEEN_PARENS)[1];
25
27
  if (functionName in fn) {
26
- const type = (_d = (_c = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.collections[table]) === null || _a === void 0 ? void 0 : _a.fields) === null || _b === void 0 ? void 0 : _b[columnName]) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : 'unknown';
28
+ const collectionName = (options === null || options === void 0 ? void 0 : options.originalCollectionName) || table;
29
+ const type = (_d = (_c = (_b = (_a = schema === null || schema === void 0 ? void 0 : schema.collections[collectionName]) === null || _a === void 0 ? void 0 : _a.fields) === null || _b === void 0 ? void 0 : _b[columnName]) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : 'unknown';
27
30
  const allowedFunctions = (0, utils_1.getFunctionsForType)(type);
28
31
  if (allowedFunctions.includes(functionName) === false) {
29
32
  throw new exceptions_1.InvalidQueryException(`Invalid function specified "${functionName}"`);
30
33
  }
31
- const result = fn[functionName](table, columnName, { type, query });
34
+ const result = fn[functionName](table, columnName, {
35
+ type,
36
+ query: options === null || options === void 0 ? void 0 : options.query,
37
+ originalCollectionName: options === null || options === void 0 ? void 0 : options.originalCollectionName,
38
+ });
32
39
  if (alias) {
33
40
  return knex.raw(result + ' AS ??', [alias]);
34
41
  }
@@ -6,10 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getConfigFromEnv = void 0;
7
7
  const camelcase_1 = __importDefault(require("camelcase"));
8
8
  const lodash_1 = require("lodash");
9
- const env_1 = __importDefault(require("../env"));
9
+ const env_1 = require("../env");
10
10
  function getConfigFromEnv(prefix, omitPrefix, type = 'camelcase') {
11
+ const env = (0, env_1.getEnv)();
11
12
  const config = {};
12
- for (const [key, value] of Object.entries(env_1.default)) {
13
+ for (const [key, value] of Object.entries(env)) {
13
14
  if (key.toLowerCase().startsWith(prefix.toLowerCase()) === false)
14
15
  continue;
15
16
  if (omitPrefix) {
@@ -1,3 +1,3 @@
1
- import { SchemaOverview } from '@directus/schema/dist/types/overview';
1
+ import { SchemaOverview } from '@directus/schema/types/overview';
2
2
  import { Column } from 'knex-schema-inspector/dist/types/column';
3
3
  export default function getDefaultValue(column: SchemaOverview[string]['columns'][string] | Column): string | boolean | number | Record<string, any> | any[] | null;
@@ -1,6 +1,10 @@
1
- import { Accountability, SchemaOverview } from '@directus/shared/types';
1
+ import { SchemaOverview } from '@directus/shared/types';
2
2
  import { Knex } from 'knex';
3
3
  export declare function getSchema(options?: {
4
- accountability?: Accountability;
5
4
  database?: Knex;
5
+ /**
6
+ * To bypass any cached schema if bypassCache is enabled.
7
+ * Used to ensure schema snapshot/apply is not using outdated schema
8
+ */
9
+ bypassCache?: boolean;
6
10
  }): Promise<SchemaOverview>;
@@ -21,7 +21,7 @@ async function getSchema(options) {
21
21
  const database = (options === null || options === void 0 ? void 0 : options.database) || (0, database_1.default)();
22
22
  const schemaInspector = (0, schema_1.default)(database);
23
23
  let result;
24
- if (env_1.default.CACHE_SCHEMA !== false) {
24
+ if (!(options === null || options === void 0 ? void 0 : options.bypassCache) && env_1.default.CACHE_SCHEMA !== false) {
25
25
  let cachedSchema;
26
26
  try {
27
27
  cachedSchema = (await (0, cache_1.getSystemCache)('schema'));
@@ -12,7 +12,7 @@ const lodash_1 = require("lodash");
12
12
  async function getSnapshot(options) {
13
13
  var _a, _b;
14
14
  const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
15
- const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database }));
15
+ const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database, bypassCache: true }));
16
16
  const collectionsService = new services_1.CollectionsService({ knex: database, schema });
17
17
  const fieldsService = new services_1.FieldsService({ knex: database, schema });
18
18
  const relationsService = new services_1.RelationsService({ knex: database, schema });
@@ -0,0 +1,3 @@
1
+ /// <reference types="node" />
2
+ export declare function parseIptc(buffer: Buffer): Record<string, unknown>;
3
+ export declare function parseXmp(buffer: Buffer): Record<string, unknown>;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseXmp = exports.parseIptc = void 0;
4
+ const IPTC_ENTRY_TYPES = new Map([
5
+ [0x78, 'caption'],
6
+ [0x6e, 'credit'],
7
+ [0x19, 'keywords'],
8
+ [0x37, 'dateCreated'],
9
+ [0x50, 'byline'],
10
+ [0x55, 'bylineTitle'],
11
+ [0x7a, 'captionWriter'],
12
+ [0x69, 'headline'],
13
+ [0x74, 'copyright'],
14
+ [0x0f, 'category'],
15
+ ]);
16
+ const IPTC_ENTRY_MARKER = Buffer.from([0x1c, 0x02]);
17
+ function parseIptc(buffer) {
18
+ if (!Buffer.isBuffer(buffer))
19
+ return {};
20
+ const iptc = {};
21
+ let lastIptcEntryPos = buffer.indexOf(IPTC_ENTRY_MARKER);
22
+ while (lastIptcEntryPos !== -1) {
23
+ lastIptcEntryPos = buffer.indexOf(IPTC_ENTRY_MARKER, lastIptcEntryPos + IPTC_ENTRY_MARKER.byteLength);
24
+ const iptcBlockTypePos = lastIptcEntryPos + IPTC_ENTRY_MARKER.byteLength;
25
+ const iptcBlockSizePos = iptcBlockTypePos + 1;
26
+ const iptcBlockDataPos = iptcBlockSizePos + 2;
27
+ const iptcBlockType = buffer.readUInt8(iptcBlockTypePos);
28
+ const iptcBlockSize = buffer.readUInt16BE(iptcBlockSizePos);
29
+ if (!IPTC_ENTRY_TYPES.has(iptcBlockType)) {
30
+ continue;
31
+ }
32
+ const iptcBlockTypeId = IPTC_ENTRY_TYPES.get(iptcBlockType);
33
+ const iptcData = buffer.subarray(iptcBlockDataPos, iptcBlockDataPos + iptcBlockSize).toString();
34
+ if (iptcBlockTypeId) {
35
+ if (iptc[iptcBlockTypeId] == null) {
36
+ iptc[iptcBlockTypeId] = iptcData;
37
+ }
38
+ else if (Array.isArray(iptc[iptcBlockTypeId])) {
39
+ iptc[iptcBlockTypeId].push(iptcData);
40
+ }
41
+ else {
42
+ iptc[iptcBlockTypeId] = [iptc[iptcBlockTypeId], iptcData];
43
+ }
44
+ }
45
+ }
46
+ return iptc;
47
+ }
48
+ exports.parseIptc = parseIptc;
49
+ function parseXmp(buffer) {
50
+ const xmp = {};
51
+ ['title', 'description', 'rights', 'creator', 'subject'].forEach((x) => {
52
+ const tagRegex = new RegExp(`<dc:${x}>(.*?)</dc:${x}>`, 'smig'), tagMatches = tagRegex.exec(buffer.toString());
53
+ if (!tagMatches || tagMatches.length === 0) {
54
+ return;
55
+ }
56
+ const value = tagMatches[1].trim();
57
+ if (value.toLowerCase().indexOf('<rdf:bag>') === 0) {
58
+ const r = new RegExp('<rdf:li>(.*?)</rdf:li>', 'smig');
59
+ let match = r.exec(value);
60
+ const result = [];
61
+ while (match) {
62
+ result.push(match[1]);
63
+ match = r.exec(value);
64
+ }
65
+ xmp[x] = result;
66
+ }
67
+ else {
68
+ xmp[x] = value.replace(/<[^>]*>?/gm, '').trim();
69
+ }
70
+ });
71
+ return xmp;
72
+ }
73
+ exports.parseXmp = parseXmp;
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.track = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
7
  const ms_1 = __importDefault(require("ms"));
9
8
  const node_machine_id_1 = require("node-machine-id");
10
9
  const os_1 = __importDefault(require("os"));
@@ -14,10 +13,11 @@ const env_1 = __importDefault(require("../env"));
14
13
  const logger_1 = __importDefault(require("../logger"));
15
14
  const utils_1 = require("@directus/shared/utils");
16
15
  async function track(event) {
16
+ const axios = (await import('axios')).default;
17
17
  if (env_1.default.TELEMETRY !== false) {
18
18
  const info = await getEnvInfo(event);
19
19
  try {
20
- await axios_1.default.post('https://telemetry.directus.io/', info);
20
+ await axios.post('https://telemetry.directus.io/', info);
21
21
  }
22
22
  catch (err) {
23
23
  if (env_1.default.NODE_ENV === 'development') {
@@ -4,11 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.validateEnv = void 0;
7
- const env_1 = __importDefault(require("../env"));
7
+ const env_1 = require("../env");
8
8
  const logger_1 = __importDefault(require("../logger"));
9
9
  function validateEnv(requiredKeys) {
10
+ const env = (0, env_1.getEnv)();
10
11
  for (const requiredKey of requiredKeys) {
11
- if (requiredKey in env_1.default === false) {
12
+ if (requiredKey in env === false) {
12
13
  logger_1.default.error(`"${requiredKey}" Environment Variable is missing.`);
13
14
  process.exit(1);
14
15
  }
package/dist/webhooks.js CHANGED
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.unregister = exports.register = exports.reload = exports.init = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
7
  const database_1 = __importDefault(require("./database"));
9
8
  const emitter_1 = __importDefault(require("./emitter"));
10
9
  const logger_1 = __importDefault(require("./logger"));
@@ -53,6 +52,7 @@ function unregister() {
53
52
  exports.unregister = unregister;
54
53
  function createHandler(webhook, event) {
55
54
  return async (meta, context) => {
55
+ const axios = (await import('axios')).default;
56
56
  if (webhook.collections.includes(meta.collection) === false)
57
57
  return;
58
58
  const webhookPayload = {
@@ -66,7 +66,7 @@ function createHandler(webhook, event) {
66
66
  ...meta,
67
67
  };
68
68
  try {
69
- await (0, axios_1.default)({
69
+ await axios({
70
70
  url: webhook.url,
71
71
  method: webhook.method,
72
72
  data: webhook.data ? webhookPayload : null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "directus",
3
- "version": "9.21.0",
3
+ "version": "9.22.0",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "keywords": [
6
6
  "directus",
@@ -66,16 +66,7 @@
66
66
  "dependencies": {
67
67
  "@authenio/samlify-node-xmllint": "2.0.0",
68
68
  "@aws-sdk/client-ses": "3.211.0",
69
- "@directus/app": "9.21.0",
70
- "@directus/drive": "9.21.0",
71
- "@directus/drive-azure": "9.21.0",
72
- "@directus/drive-gcs": "9.21.0",
73
- "@directus/drive-s3": "9.21.0",
74
- "@directus/extensions-sdk": "9.21.0",
75
69
  "@directus/format-title": "9.15.0",
76
- "@directus/schema": "9.21.0",
77
- "@directus/shared": "9.21.0",
78
- "@directus/specs": "9.21.0",
79
70
  "@godaddy/terminus": "4.11.2",
80
71
  "@rollup/plugin-alias": "4.0.2",
81
72
  "@rollup/plugin-virtual": "3.0.1",
@@ -94,13 +85,12 @@
94
85
  "csv-parser": "3.0.0",
95
86
  "date-fns": "2.29.3",
96
87
  "deep-diff": "1.0.2",
97
- "deep-map": "2.0.0",
98
88
  "destroy": "1.2.0",
99
89
  "dotenv": "16.0.3",
100
90
  "encodeurl": "1.0.2",
101
91
  "eventemitter2": "6.4.9",
102
92
  "execa": "5.1.1",
103
- "exifr": "7.1.3",
93
+ "exif-reader": "1.0.3",
104
94
  "express": "4.18.2",
105
95
  "fast-redact": "3.1.2",
106
96
  "flat": "5.0.2",
@@ -109,6 +99,7 @@
109
99
  "graphql": "16.6.0",
110
100
  "graphql-compose": "9.0.10",
111
101
  "helmet": "6.0.0",
102
+ "icc": "2.0.0",
112
103
  "inquirer": "8.2.4",
113
104
  "ioredis": "5.2.4",
114
105
  "joi": "17.7.0",
@@ -138,9 +129,9 @@
138
129
  "pino": "8.7.0",
139
130
  "pino-http": "8.2.1",
140
131
  "pino-http-print": "3.1.0",
132
+ "pino-pretty": "9.1.1",
141
133
  "qs": "6.11.0",
142
134
  "rate-limiter-flexible": "2.4.1",
143
- "resolve-cwd": "3.0.0",
144
135
  "rollup": "3.3.0",
145
136
  "samlify": "2.8.7",
146
137
  "sanitize-html": "2.7.3",
@@ -153,10 +144,21 @@
153
144
  "uuid": "9.0.0",
154
145
  "uuid-validate": "0.0.3",
155
146
  "vm2": "3.9.11",
156
- "wellknown": "0.5.0"
147
+ "wellknown": "0.5.0",
148
+ "@directus/app": "9.22.0",
149
+ "@directus/extensions-sdk": "9.22.0",
150
+ "@directus/schema": "9.22.0",
151
+ "@directus/shared": "9.22.0",
152
+ "@directus/specs": "9.22.0",
153
+ "@directus/storage": "9.22.0",
154
+ "@directus/storage-driver-azure": "9.22.0",
155
+ "@directus/storage-driver-cloudinary": "9.21.2",
156
+ "@directus/storage-driver-gcs": "9.22.0",
157
+ "@directus/storage-driver-local": "9.22.0",
158
+ "@directus/storage-driver-s3": "9.22.0"
157
159
  },
158
160
  "devDependencies": {
159
- "@otplib/preset-default": "12.0.1",
161
+ "@ngneat/falso": "6.3.0",
160
162
  "@types/async": "3.2.15",
161
163
  "@types/busboy": "1.5.0",
162
164
  "@types/bytes": "3.1.1",
@@ -165,10 +167,9 @@
165
167
  "@types/deep-diff": "1.0.1",
166
168
  "@types/destroy": "1.0.0",
167
169
  "@types/encodeurl": "1.0.0",
170
+ "@types/exif-reader": "1.0.0",
168
171
  "@types/express": "4.17.14",
169
- "@types/express-pino-logger": "4.0.3",
170
172
  "@types/express-serve-static-core": "4.17.31",
171
- "@types/express-session": "1.17.5",
172
173
  "@types/fast-redact": "3.0.2",
173
174
  "@types/flat": "5.0.2",
174
175
  "@types/fs-extra": "9.0.13",
@@ -192,7 +193,6 @@
192
193
  "@types/sanitize-html": "2.6.2",
193
194
  "@types/sharp": "0.31.0",
194
195
  "@types/stream-json": "1.7.2",
195
- "@types/supertest": "2.0.12",
196
196
  "@types/uuid": "8.3.4",
197
197
  "@types/uuid-validate": "0.0.1",
198
198
  "@types/wellknown": "0.5.4",
@@ -200,8 +200,6 @@
200
200
  "copyfiles": "2.4.1",
201
201
  "form-data": "4.0.0",
202
202
  "knex-mock-client": "1.8.4",
203
- "rimraf": "3.0.2",
204
- "supertest": "6.3.1",
205
203
  "ts-node": "10.9.1",
206
204
  "ts-node-dev": "2.0.0",
207
205
  "typescript": "4.9.3",
@@ -222,9 +220,7 @@
222
220
  "node": ">=12.20.0"
223
221
  },
224
222
  "scripts": {
225
- "prebuild": "pnpm cleanup",
226
223
  "build": "tsc --build && copyfiles \"src/**/*.{yaml,liquid}\" -u 1 dist",
227
- "cleanup": "rimraf dist",
228
224
  "cli": "NODE_ENV=development SERVE_APP=false ts-node --script-mode --transpile-only src/cli/run.ts",
229
225
  "dev": "NODE_ENV=development SERVE_APP=false ts-node-dev --files --transpile-only --respawn --watch \".env\" --inspect=0 --exit-child -- src/start.ts",
230
226
  "start": "npx directus start",