directus 9.12.0 → 9.13.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 (133) hide show
  1. package/dist/app.js +11 -1
  2. package/dist/auth/drivers/index.js +5 -1
  3. package/dist/auth/drivers/ldap.js +5 -1
  4. package/dist/auth/drivers/oauth2.js +15 -23
  5. package/dist/auth/drivers/openid.js +16 -24
  6. package/dist/cli/commands/bootstrap/index.js +5 -1
  7. package/dist/cli/commands/schema/apply.js +7 -3
  8. package/dist/cli/commands/schema/snapshot.d.ts +1 -1
  9. package/dist/cli/commands/schema/snapshot.js +33 -25
  10. package/dist/cli/index.js +1 -1
  11. package/dist/cli/utils/create-env/env-stub.liquid +11 -11
  12. package/dist/constants.d.ts +1 -0
  13. package/dist/constants.js +5 -1
  14. package/dist/controllers/assets.js +5 -5
  15. package/dist/controllers/dashboards.js +4 -1
  16. package/dist/controllers/files.js +8 -5
  17. package/dist/controllers/flows.js +4 -1
  18. package/dist/controllers/folders.js +4 -1
  19. package/dist/controllers/items.js +4 -1
  20. package/dist/controllers/notifications.js +4 -1
  21. package/dist/controllers/operations.js +4 -1
  22. package/dist/controllers/panels.js +4 -1
  23. package/dist/controllers/permissions.js +4 -1
  24. package/dist/controllers/presets.js +4 -1
  25. package/dist/controllers/roles.js +4 -1
  26. package/dist/controllers/shares.js +4 -1
  27. package/dist/controllers/users.js +75 -3
  28. package/dist/controllers/utils.js +3 -3
  29. package/dist/database/helpers/date/dialects/sqlite.js +3 -0
  30. package/dist/database/helpers/fn/dialects/oracle.d.ts +9 -9
  31. package/dist/database/helpers/fn/dialects/oracle.js +22 -16
  32. package/dist/database/helpers/fn/dialects/sqlite.d.ts +9 -9
  33. package/dist/database/helpers/fn/dialects/sqlite.js +46 -16
  34. package/dist/database/helpers/fn/types.d.ts +12 -9
  35. package/dist/database/helpers/index.js +5 -1
  36. package/dist/database/index.js +2 -0
  37. package/dist/database/migrations/20210225A-add-relations-sort-field.js +2 -2
  38. package/dist/database/migrations/20210506A-rename-interfaces.js +2 -2
  39. package/dist/database/migrations/20210802A-replace-groups.js +2 -2
  40. package/dist/database/migrations/20210805A-update-groups.js +2 -2
  41. package/dist/database/migrations/20210805B-change-image-metadata-structure.js +3 -3
  42. package/dist/database/migrations/20211007A-update-presets.js +5 -5
  43. package/dist/database/migrations/20220429A-add-flows.js +1 -2
  44. package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.d.ts +3 -0
  45. package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.js +11 -0
  46. package/dist/database/system-data/fields/dashboards.yaml +1 -0
  47. package/dist/database/system-data/fields/flows.yaml +1 -1
  48. package/dist/env.d.ts +1 -1
  49. package/dist/env.js +8 -3
  50. package/dist/exceptions/database/translate.js +5 -1
  51. package/dist/exceptions/index.js +5 -1
  52. package/dist/extensions.d.ts +2 -1
  53. package/dist/extensions.js +31 -23
  54. package/dist/flows.d.ts +5 -0
  55. package/dist/flows.js +66 -40
  56. package/dist/index.js +5 -1
  57. package/dist/logger.js +5 -1
  58. package/dist/messenger.js +2 -2
  59. package/dist/middleware/graphql.js +2 -2
  60. package/dist/middleware/respond.js +10 -1
  61. package/dist/middleware/validate-batch.js +3 -1
  62. package/dist/operations/item-create/index.js +1 -2
  63. package/dist/operations/item-delete/index.d.ts +1 -0
  64. package/dist/operations/item-delete/index.js +8 -7
  65. package/dist/operations/item-read/index.js +7 -6
  66. package/dist/operations/item-update/index.d.ts +1 -0
  67. package/dist/operations/item-update/index.js +9 -8
  68. package/dist/operations/log/index.js +1 -2
  69. package/dist/operations/notification/index.js +1 -2
  70. package/dist/operations/request/index.d.ts +4 -1
  71. package/dist/operations/request/index.js +5 -1
  72. package/dist/operations/transform/index.js +1 -2
  73. package/dist/operations/trigger/index.js +1 -2
  74. package/dist/server.js +5 -1
  75. package/dist/services/assets.js +5 -1
  76. package/dist/services/collections.js +5 -1
  77. package/dist/services/fields.d.ts +3 -3
  78. package/dist/services/fields.js +25 -17
  79. package/dist/services/files.js +5 -1
  80. package/dist/services/flows.d.ts +1 -2
  81. package/dist/services/flows.js +19 -8
  82. package/dist/services/{graphql.d.ts → graphql/index.d.ts} +3 -5
  83. package/dist/services/{graphql.js → graphql/index.js} +115 -102
  84. package/dist/services/graphql/types/date.d.ts +2 -0
  85. package/dist/services/graphql/types/date.js +9 -0
  86. package/dist/services/graphql/types/geojson.d.ts +2 -0
  87. package/dist/services/graphql/types/geojson.js +10 -0
  88. package/dist/services/graphql/types/string-or-float.d.ts +5 -0
  89. package/dist/services/graphql/types/string-or-float.js +34 -0
  90. package/dist/services/graphql/types/void.d.ts +2 -0
  91. package/dist/services/graphql/types/void.js +17 -0
  92. package/dist/services/graphql/utils/add-path-to-validation-error.d.ts +2 -0
  93. package/dist/services/graphql/utils/add-path-to-validation-error.js +20 -0
  94. package/dist/services/import-export.js +13 -10
  95. package/dist/services/index.js +5 -1
  96. package/dist/services/items.d.ts +5 -1
  97. package/dist/services/items.js +22 -2
  98. package/dist/services/mail/index.js +8 -6
  99. package/dist/services/operations.d.ts +1 -2
  100. package/dist/services/operations.js +19 -8
  101. package/dist/services/payload.js +2 -3
  102. package/dist/services/permissions.d.ts +1 -0
  103. package/dist/services/permissions.js +5 -0
  104. package/dist/services/relations.js +5 -1
  105. package/dist/services/roles.d.ts +1 -0
  106. package/dist/services/roles.js +9 -0
  107. package/dist/services/server.js +5 -1
  108. package/dist/services/users.d.ts +1 -0
  109. package/dist/services/users.js +22 -0
  110. package/dist/types/index.js +5 -1
  111. package/dist/utils/apply-query.js +24 -15
  112. package/dist/utils/apply-snapshot.js +3 -0
  113. package/dist/utils/calculate-field-depth.d.ts +33 -0
  114. package/dist/utils/calculate-field-depth.js +75 -0
  115. package/dist/utils/get-column.js +1 -1
  116. package/dist/utils/get-default-value.js +3 -13
  117. package/dist/utils/get-graphql-type.js +4 -3
  118. package/dist/utils/get-local-type.d.ts +6 -3
  119. package/dist/utils/get-permissions.js +3 -4
  120. package/dist/utils/get-schema.js +1 -2
  121. package/dist/utils/get-string-byte-size.d.ts +4 -0
  122. package/dist/utils/get-string-byte-size.js +10 -0
  123. package/dist/utils/job-queue.d.ts +9 -0
  124. package/dist/utils/job-queue.js +24 -0
  125. package/dist/utils/jwt.js +5 -1
  126. package/dist/utils/sanitize-query.js +4 -5
  127. package/dist/utils/validate-query.js +50 -0
  128. package/dist/webhooks.js +5 -1
  129. package/package.json +75 -74
  130. package/dist/utils/operation-options.d.ts +0 -3
  131. package/dist/utils/operation-options.js +0 -45
  132. package/dist/utils/parse-json.d.ts +0 -5
  133. package/dist/utils/parse-json.js +0 -19
@@ -3,70 +3,56 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.GraphQLService = exports.GraphQLDate = exports.GraphQLGeoJSON = void 0;
6
+ exports.GraphQLService = void 0;
7
7
  const types_1 = require("@directus/shared/types");
8
8
  const argon2_1 = __importDefault(require("argon2"));
9
9
  const graphql_1 = require("graphql");
10
10
  const graphql_compose_1 = require("graphql-compose");
11
11
  const lodash_1 = require("lodash");
12
12
  const ms_1 = __importDefault(require("ms"));
13
- const cache_1 = require("../cache");
14
- const constants_1 = require("../constants");
15
- const database_1 = __importDefault(require("../database"));
16
- const env_1 = __importDefault(require("../env"));
17
- const exceptions_1 = require("../exceptions");
18
- const extensions_1 = require("../extensions");
19
- const generate_hash_1 = require("../utils/generate-hash");
20
- const get_graphql_type_1 = require("../utils/get-graphql-type");
21
- const reduce_schema_1 = require("../utils/reduce-schema");
22
- const sanitize_query_1 = require("../utils/sanitize-query");
23
- const validate_query_1 = require("../utils/validate-query");
24
- const activity_1 = require("./activity");
25
- const authentication_1 = require("./authentication");
26
- const collections_1 = require("./collections");
27
- const fields_1 = require("./fields");
28
- const files_1 = require("./files");
29
- const flows_1 = require("./flows");
30
- const folders_1 = require("./folders");
31
- const items_1 = require("./items");
32
- const notifications_1 = require("./notifications");
33
- const operations_1 = require("./operations");
34
- const permissions_1 = require("./permissions");
35
- const presets_1 = require("./presets");
36
- const relations_1 = require("./relations");
37
- const revisions_1 = require("./revisions");
38
- const roles_1 = require("./roles");
39
- const server_1 = require("./server");
40
- const settings_1 = require("./settings");
41
- const shares_1 = require("./shares");
42
- const specifications_1 = require("./specifications");
43
- const tfa_1 = require("./tfa");
44
- const users_1 = require("./users");
45
- const utils_1 = require("./utils");
46
- const webhooks_1 = require("./webhooks");
47
- const GraphQLVoid = new graphql_1.GraphQLScalarType({
48
- name: 'Void',
49
- description: 'Represents NULL values',
50
- serialize() {
51
- return null;
52
- },
53
- parseValue() {
54
- return null;
55
- },
56
- parseLiteral() {
57
- return null;
58
- },
59
- });
60
- exports.GraphQLGeoJSON = new graphql_1.GraphQLScalarType({
61
- ...graphql_compose_1.GraphQLJSON,
62
- name: 'GraphQLGeoJSON',
63
- description: 'GeoJSON value',
64
- });
65
- exports.GraphQLDate = new graphql_1.GraphQLScalarType({
66
- ...graphql_1.GraphQLString,
67
- name: 'Date',
68
- description: 'ISO8601 Date values',
69
- });
13
+ const cache_1 = require("../../cache");
14
+ const constants_1 = require("../../constants");
15
+ const database_1 = __importDefault(require("../../database"));
16
+ const env_1 = __importDefault(require("../../env"));
17
+ const exceptions_1 = require("../../exceptions");
18
+ const extensions_1 = require("../../extensions");
19
+ const generate_hash_1 = require("../../utils/generate-hash");
20
+ const get_graphql_type_1 = require("../../utils/get-graphql-type");
21
+ const reduce_schema_1 = require("../../utils/reduce-schema");
22
+ const sanitize_query_1 = require("../../utils/sanitize-query");
23
+ const validate_query_1 = require("../../utils/validate-query");
24
+ const activity_1 = require("../activity");
25
+ const authentication_1 = require("../authentication");
26
+ const collections_1 = require("../collections");
27
+ const fields_1 = require("../fields");
28
+ const files_1 = require("../files");
29
+ const flows_1 = require("../flows");
30
+ const folders_1 = require("../folders");
31
+ const items_1 = require("../items");
32
+ const notifications_1 = require("../notifications");
33
+ const operations_1 = require("../operations");
34
+ const permissions_1 = require("../permissions");
35
+ const presets_1 = require("../presets");
36
+ const relations_1 = require("../relations");
37
+ const revisions_1 = require("../revisions");
38
+ const roles_1 = require("../roles");
39
+ const server_1 = require("../server");
40
+ const settings_1 = require("../settings");
41
+ const shares_1 = require("../shares");
42
+ const specifications_1 = require("../specifications");
43
+ const tfa_1 = require("../tfa");
44
+ const users_1 = require("../users");
45
+ const utils_1 = require("../utils");
46
+ const webhooks_1 = require("../webhooks");
47
+ const date_1 = require("./types/date");
48
+ const geojson_1 = require("./types/geojson");
49
+ const string_or_float_1 = require("./types/string-or-float");
50
+ const void_1 = require("./types/void");
51
+ const add_path_to_validation_error_1 = require("./utils/add-path-to-validation-error");
52
+ const validationRules = Array.from(graphql_1.specifiedRules);
53
+ if (env_1.default.GRAPHQL_INTROSPECTION === false) {
54
+ validationRules.push(graphql_1.NoSchemaIntrospectionCustomRule);
55
+ }
70
56
  /**
71
57
  * These should be ignored in the context of GraphQL, and/or are replaced by a custom resolver (for non-standard structures)
72
58
  */
@@ -91,16 +77,7 @@ class GraphQLService {
91
77
  async execute({ document, variables, operationName, contextValue, }) {
92
78
  var _a;
93
79
  const schema = this.getSchema();
94
- const validationErrors = (0, graphql_1.validate)(schema, document, [
95
- ...graphql_1.specifiedRules,
96
- (context) => ({
97
- Field(node) {
98
- if (env_1.default.GRAPHQL_INTROSPECTION === false && (node.name.value === '__schema' || node.name.value === '__type')) {
99
- context.reportError(new graphql_1.GraphQLError('GraphQL introspection is not allowed. The query contained __schema or __type.', [node]));
100
- }
101
- },
102
- }),
103
- ]);
80
+ const validationErrors = (0, graphql_1.validate)(schema, document, validationRules).map((validationError) => (0, add_path_to_validation_error_1.addPathToValidationError)(validationError));
104
81
  if (validationErrors.length > 0) {
105
82
  throw new exceptions_1.GraphQLValidationException({ graphqlErrors: validationErrors });
106
83
  }
@@ -180,7 +157,7 @@ class GraphQLService {
180
157
  else {
181
158
  schemaComposer.Query.addFields({
182
159
  _empty: {
183
- type: GraphQLVoid,
160
+ type: void_1.GraphQLVoid,
184
161
  description: "There's no data to query.",
185
162
  },
186
163
  });
@@ -209,6 +186,7 @@ class GraphQLService {
209
186
  }
210
187
  else {
211
188
  acc[`update_${collectionName}_items`] = UpdateCollectionTypes[collection.collection].getResolver(`update_${collection.collection}_items`);
189
+ acc[`update_${collectionName}_batch`] = UpdateCollectionTypes[collection.collection].getResolver(`update_${collection.collection}_batch`);
212
190
  acc[`update_${collectionName}_item`] = UpdateCollectionTypes[collection.collection].getResolver(`update_${collection.collection}_item`);
213
191
  }
214
192
  return acc;
@@ -512,32 +490,33 @@ class GraphQLService {
512
490
  },
513
491
  },
514
492
  });
493
+ // Uses StringOrFloat rather than Float to support api dynamic variables (like `$NOW`)
515
494
  const NumberFilterOperators = schemaComposer.createInputTC({
516
495
  name: 'number_filter_operators',
517
496
  fields: {
518
497
  _eq: {
519
- type: graphql_1.GraphQLFloat,
498
+ type: string_or_float_1.GraphQLStringOrFloat,
520
499
  },
521
500
  _neq: {
522
- type: graphql_1.GraphQLFloat,
501
+ type: string_or_float_1.GraphQLStringOrFloat,
523
502
  },
524
503
  _in: {
525
- type: new graphql_1.GraphQLList(graphql_1.GraphQLFloat),
504
+ type: new graphql_1.GraphQLList(string_or_float_1.GraphQLStringOrFloat),
526
505
  },
527
506
  _nin: {
528
- type: new graphql_1.GraphQLList(graphql_1.GraphQLFloat),
507
+ type: new graphql_1.GraphQLList(string_or_float_1.GraphQLStringOrFloat),
529
508
  },
530
509
  _gt: {
531
- type: graphql_1.GraphQLFloat,
510
+ type: string_or_float_1.GraphQLStringOrFloat,
532
511
  },
533
512
  _gte: {
534
- type: graphql_1.GraphQLFloat,
513
+ type: string_or_float_1.GraphQLStringOrFloat,
535
514
  },
536
515
  _lt: {
537
- type: graphql_1.GraphQLFloat,
516
+ type: string_or_float_1.GraphQLStringOrFloat,
538
517
  },
539
518
  _lte: {
540
- type: graphql_1.GraphQLFloat,
519
+ type: string_or_float_1.GraphQLStringOrFloat,
541
520
  },
542
521
  _null: {
543
522
  type: graphql_1.GraphQLBoolean,
@@ -551,22 +530,22 @@ class GraphQLService {
551
530
  name: 'geometry_filter_operators',
552
531
  fields: {
553
532
  _eq: {
554
- type: exports.GraphQLGeoJSON,
533
+ type: geojson_1.GraphQLGeoJSON,
555
534
  },
556
535
  _neq: {
557
- type: exports.GraphQLGeoJSON,
536
+ type: geojson_1.GraphQLGeoJSON,
558
537
  },
559
538
  _intersects: {
560
- type: exports.GraphQLGeoJSON,
539
+ type: geojson_1.GraphQLGeoJSON,
561
540
  },
562
541
  _nintersects: {
563
- type: exports.GraphQLGeoJSON,
542
+ type: geojson_1.GraphQLGeoJSON,
564
543
  },
565
544
  _intersects_bbox: {
566
- type: exports.GraphQLGeoJSON,
545
+ type: geojson_1.GraphQLGeoJSON,
567
546
  },
568
547
  _nintersects_bbox: {
569
- type: exports.GraphQLGeoJSON,
548
+ type: geojson_1.GraphQLGeoJSON,
570
549
  },
571
550
  },
572
551
  });
@@ -637,10 +616,10 @@ class GraphQLService {
637
616
  case graphql_1.GraphQLFloat:
638
617
  filterOperatorType = NumberFilterOperators;
639
618
  break;
640
- case exports.GraphQLDate:
619
+ case date_1.GraphQLDate:
641
620
  filterOperatorType = DateFilterOperators;
642
621
  break;
643
- case exports.GraphQLGeoJSON:
622
+ case geojson_1.GraphQLGeoJSON:
644
623
  filterOperatorType = GeometryFilterOperators;
645
624
  break;
646
625
  default:
@@ -782,7 +761,7 @@ class GraphQLService {
782
761
  },
783
762
  type: collection.singleton
784
763
  ? ReadCollectionTypes[collection.collection]
785
- : [ReadCollectionTypes[collection.collection]],
764
+ : new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(ReadCollectionTypes[collection.collection].getType()))),
786
765
  resolve: async ({ info, context }) => {
787
766
  const result = await self.resolveQuery(info);
788
767
  context.data = result;
@@ -791,7 +770,7 @@ class GraphQLService {
791
770
  });
792
771
  ReadCollectionTypes[collection.collection].addResolver({
793
772
  name: `${collection.collection}_aggregated`,
794
- type: [AggregatedFunctions[collection.collection]],
773
+ type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(AggregatedFunctions[collection.collection].getType()))),
795
774
  args: {
796
775
  groupBy: new graphql_1.GraphQLList(graphql_1.GraphQLString),
797
776
  filter: ReadableCollectionFilterTypes[collection.collection],
@@ -901,7 +880,9 @@ class GraphQLService {
901
880
  if (Object.keys(creatableFields).length > 0) {
902
881
  CreateCollectionTypes[collection.collection].addResolver({
903
882
  name: `create_${collection.collection}_items`,
904
- type: collectionIsReadable ? [ReadCollectionTypes[collection.collection]] : graphql_1.GraphQLBoolean,
883
+ type: collectionIsReadable
884
+ ? new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(ReadCollectionTypes[collection.collection].getType())))
885
+ : graphql_1.GraphQLBoolean,
905
886
  args: collectionIsReadable
906
887
  ? ReadCollectionTypes[collection.collection].getResolver(collection.collection).getArgs()
907
888
  : undefined,
@@ -949,9 +930,26 @@ class GraphQLService {
949
930
  });
950
931
  }
951
932
  else {
933
+ UpdateCollectionTypes[collection.collection].addResolver({
934
+ name: `update_${collection.collection}_batch`,
935
+ type: collectionIsReadable
936
+ ? new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(ReadCollectionTypes[collection.collection].getType())))
937
+ : graphql_1.GraphQLBoolean,
938
+ args: {
939
+ ...(collectionIsReadable
940
+ ? ReadCollectionTypes[collection.collection].getResolver(collection.collection).getArgs()
941
+ : {}),
942
+ data: [
943
+ (0, graphql_compose_1.toInputObjectType)(UpdateCollectionTypes[collection.collection]).setTypeName(`update_${collection.collection}_input`).NonNull,
944
+ ],
945
+ },
946
+ resolve: async ({ args, info }) => await self.resolveMutation(args, info),
947
+ });
952
948
  UpdateCollectionTypes[collection.collection].addResolver({
953
949
  name: `update_${collection.collection}_items`,
954
- type: collectionIsReadable ? [ReadCollectionTypes[collection.collection]] : graphql_1.GraphQLBoolean,
950
+ type: collectionIsReadable
951
+ ? new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(ReadCollectionTypes[collection.collection].getType())))
952
+ : graphql_1.GraphQLBoolean,
955
953
  args: {
956
954
  ...(collectionIsReadable
957
955
  ? ReadCollectionTypes[collection.collection].getResolver(collection.collection).getArgs()
@@ -1065,10 +1063,14 @@ class GraphQLService {
1065
1063
  collection = `directus_${collection}`;
1066
1064
  const selections = this.replaceFragmentsInSelections((_b = (_a = info.fieldNodes[0]) === null || _a === void 0 ? void 0 : _a.selectionSet) === null || _b === void 0 ? void 0 : _b.selections, info.fragments);
1067
1065
  const query = this.getQuery(args, selections || [], info.variableValues);
1068
- const singleton = collection.endsWith('_items') === false &&
1066
+ const singleton = collection.endsWith('_batch') === false &&
1067
+ collection.endsWith('_items') === false &&
1069
1068
  collection.endsWith('_item') === false &&
1070
1069
  collection in this.schema.collections;
1071
- const single = collection.endsWith('_items') === false;
1070
+ const single = collection.endsWith('_items') === false && collection.endsWith('_batch') === false;
1071
+ const batchUpdate = action === 'update' && collection.endsWith('_batch');
1072
+ if (collection.endsWith('_batch'))
1073
+ collection = collection.slice(0, -6);
1072
1074
  if (collection.endsWith('_items'))
1073
1075
  collection = collection.slice(0, -6);
1074
1076
  if (collection.endsWith('_item'))
@@ -1099,7 +1101,13 @@ class GraphQLService {
1099
1101
  return hasQuery ? await service.readMany(keys, query) : true;
1100
1102
  }
1101
1103
  if (action === 'update') {
1102
- const keys = await service.updateMany(args.ids, args.data);
1104
+ const keys = [];
1105
+ if (batchUpdate) {
1106
+ keys.push(...(await service.updateBatch(args.data)));
1107
+ }
1108
+ else {
1109
+ keys.push(...(await service.updateMany(args.ids, args.data)));
1110
+ }
1103
1111
  return hasQuery ? await service.readMany(keys, query) : true;
1104
1112
  }
1105
1113
  if (action === 'delete') {
@@ -1167,7 +1175,12 @@ class GraphQLService {
1167
1175
  values.push(this.parseArgs(valueNode.fields, variableValues));
1168
1176
  }
1169
1177
  else {
1170
- values.push(valueNode.value);
1178
+ if (valueNode.kind === 'Variable') {
1179
+ values.push(variableValues[valueNode.name.value]);
1180
+ }
1181
+ else {
1182
+ values.push(valueNode.value);
1183
+ }
1171
1184
  }
1172
1185
  }
1173
1186
  argsObject[argument.name.value] = values;
@@ -1227,7 +1240,7 @@ class GraphQLService {
1227
1240
  if (selection.selectionSet) {
1228
1241
  if (!query.deep)
1229
1242
  query.deep = {};
1230
- (0, lodash_1.set)(query.deep, parent, (0, lodash_1.merge)((0, lodash_1.get)(query.deep, parent), { _alias: { [selection.alias.value]: selection.name.value } }));
1243
+ (0, lodash_1.set)(query.deep, parent, (0, lodash_1.merge)({}, (0, lodash_1.get)(query.deep, parent), { _alias: { [selection.alias.value]: selection.name.value } }));
1231
1244
  }
1232
1245
  }
1233
1246
  }
@@ -1256,7 +1269,7 @@ class GraphQLService {
1256
1269
  if (!query.deep)
1257
1270
  query.deep = {};
1258
1271
  const args = this.parseArgs(selection.arguments, variableValues);
1259
- (0, lodash_1.set)(query.deep, currentAlias !== null && currentAlias !== void 0 ? currentAlias : current, (0, lodash_1.merge)((0, lodash_1.get)(query.deep, currentAlias !== null && currentAlias !== void 0 ? currentAlias : current), (0, lodash_1.mapKeys)((0, sanitize_query_1.sanitizeQuery)(args, this.accountability), (value, key) => `_${key}`)));
1272
+ (0, lodash_1.set)(query.deep, currentAlias !== null && currentAlias !== void 0 ? currentAlias : current, (0, lodash_1.merge)({}, (0, lodash_1.get)(query.deep, currentAlias !== null && currentAlias !== void 0 ? currentAlias : current), (0, lodash_1.mapKeys)((0, sanitize_query_1.sanitizeQuery)(args, this.accountability), (value, key) => `_${key}`)));
1260
1273
  }
1261
1274
  }
1262
1275
  }
@@ -1302,7 +1315,7 @@ class GraphQLService {
1302
1315
  continue;
1303
1316
  const aggregateProperty = aggregationGroup.name.value;
1304
1317
  query.aggregate[aggregateProperty] =
1305
- (_b = (_a = aggregationGroup.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.filter((selectionNode) => { var _a; return !((_a = selectionNode) === null || _a === void 0 ? void 0 : _a.name.value.startsWith('__')); }).map((selectionNode) => {
1318
+ (_b = (_a = aggregationGroup.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.filter((selectionNode) => !(selectionNode === null || selectionNode === void 0 ? void 0 : selectionNode.name.value.startsWith('__'))).map((selectionNode) => {
1306
1319
  selectionNode = selectionNode;
1307
1320
  return selectionNode.name.value;
1308
1321
  })) !== null && _b !== void 0 ? _b : [];
@@ -1803,7 +1816,7 @@ class GraphQLService {
1803
1816
  },
1804
1817
  },
1805
1818
  utils_cache_clear: {
1806
- type: GraphQLVoid,
1819
+ type: void_1.GraphQLVoid,
1807
1820
  resolve: async () => {
1808
1821
  var _a;
1809
1822
  if (((_a = this.accountability) === null || _a === void 0 ? void 0 : _a.admin) !== true) {
@@ -1854,7 +1867,7 @@ class GraphQLService {
1854
1867
  });
1855
1868
  schemaComposer.Query.addFields({
1856
1869
  collections: {
1857
- type: [Collection],
1870
+ type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(Collection.getType()))),
1858
1871
  resolve: async () => {
1859
1872
  const collectionsService = new collections_1.CollectionsService({
1860
1873
  accountability: this.accountability,
@@ -1915,7 +1928,7 @@ class GraphQLService {
1915
1928
  });
1916
1929
  schemaComposer.Query.addFields({
1917
1930
  fields: {
1918
- type: [Field],
1931
+ type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(Field.getType()))),
1919
1932
  resolve: async () => {
1920
1933
  const service = new fields_1.FieldsService({
1921
1934
  accountability: this.accountability,
@@ -1925,7 +1938,7 @@ class GraphQLService {
1925
1938
  },
1926
1939
  },
1927
1940
  fields_in_collection: {
1928
- type: [Field],
1941
+ type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(Field.getType()))),
1929
1942
  args: {
1930
1943
  collection: (0, graphql_1.GraphQLNonNull)(graphql_1.GraphQLString),
1931
1944
  },
@@ -1983,7 +1996,7 @@ class GraphQLService {
1983
1996
  });
1984
1997
  schemaComposer.Query.addFields({
1985
1998
  relations: {
1986
- type: [Relation],
1999
+ type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(Relation.getType()))),
1987
2000
  resolve: async () => {
1988
2001
  const service = new relations_1.RelationsService({
1989
2002
  accountability: this.accountability,
@@ -1993,7 +2006,7 @@ class GraphQLService {
1993
2006
  },
1994
2007
  },
1995
2008
  relations_in_collection: {
1996
- type: [Relation],
2009
+ type: new graphql_1.GraphQLNonNull(new graphql_1.GraphQLList(new graphql_1.GraphQLNonNull(Relation.getType()))),
1997
2010
  args: {
1998
2011
  collection: (0, graphql_1.GraphQLNonNull)(graphql_1.GraphQLString),
1999
2012
  },
@@ -0,0 +1,2 @@
1
+ import { GraphQLScalarType } from 'graphql';
2
+ export declare const GraphQLDate: GraphQLScalarType;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GraphQLDate = void 0;
4
+ const graphql_1 = require("graphql");
5
+ exports.GraphQLDate = new graphql_1.GraphQLScalarType({
6
+ ...graphql_1.GraphQLString,
7
+ name: 'Date',
8
+ description: 'ISO8601 Date values',
9
+ });
@@ -0,0 +1,2 @@
1
+ import { GraphQLScalarType } from 'graphql';
2
+ export declare const GraphQLGeoJSON: GraphQLScalarType;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GraphQLGeoJSON = void 0;
4
+ const graphql_1 = require("graphql");
5
+ const graphql_compose_1 = require("graphql-compose");
6
+ exports.GraphQLGeoJSON = new graphql_1.GraphQLScalarType({
7
+ ...graphql_compose_1.GraphQLJSON,
8
+ name: 'GraphQLGeoJSON',
9
+ description: 'GeoJSON value',
10
+ });
@@ -0,0 +1,5 @@
1
+ import { GraphQLScalarType } from 'graphql';
2
+ /**
3
+ * Adopted from https://kamranicus.com/handling-multiple-scalar-types-in-graphql/
4
+ */
5
+ export declare const GraphQLStringOrFloat: GraphQLScalarType;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GraphQLStringOrFloat = void 0;
4
+ const graphql_1 = require("graphql");
5
+ /**
6
+ * Adopted from https://kamranicus.com/handling-multiple-scalar-types-in-graphql/
7
+ */
8
+ exports.GraphQLStringOrFloat = new graphql_1.GraphQLScalarType({
9
+ name: 'GraphQLStringOrFloat',
10
+ description: 'A Float or a String',
11
+ serialize(value) {
12
+ if (typeof value !== 'string' && typeof value !== 'number') {
13
+ throw new Error('Value must be either a String or a Float');
14
+ }
15
+ return value;
16
+ },
17
+ parseValue(value) {
18
+ if (typeof value !== 'string' && typeof value !== 'number') {
19
+ throw new Error('Value must be either a String or a Float');
20
+ }
21
+ return value;
22
+ },
23
+ parseLiteral(ast) {
24
+ switch (ast.kind) {
25
+ case graphql_1.Kind.INT:
26
+ case graphql_1.Kind.FLOAT:
27
+ return Number(ast.value);
28
+ case graphql_1.Kind.STRING:
29
+ return ast.value;
30
+ default:
31
+ throw new Error('Value must be either a String or a Float');
32
+ }
33
+ },
34
+ });
@@ -0,0 +1,2 @@
1
+ import { GraphQLScalarType } from 'graphql';
2
+ export declare const GraphQLVoid: GraphQLScalarType;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GraphQLVoid = void 0;
4
+ const graphql_1 = require("graphql");
5
+ exports.GraphQLVoid = new graphql_1.GraphQLScalarType({
6
+ name: 'Void',
7
+ description: 'Represents NULL values',
8
+ serialize() {
9
+ return null;
10
+ },
11
+ parseValue() {
12
+ return null;
13
+ },
14
+ parseLiteral() {
15
+ return null;
16
+ },
17
+ });
@@ -0,0 +1,2 @@
1
+ import { GraphQLError } from 'graphql';
2
+ export declare function addPathToValidationError(validationError: GraphQLError): GraphQLError;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addPathToValidationError = void 0;
4
+ const graphql_1 = require("graphql");
5
+ function addPathToValidationError(validationError) {
6
+ var _a, _b, _c;
7
+ const token = (_c = (_b = (_a = validationError.nodes) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.loc) === null || _c === void 0 ? void 0 : _c.startToken;
8
+ if (!token)
9
+ return validationError;
10
+ let prev = token;
11
+ const queryRegex = /query_[A-Za-z0-9]{8}/;
12
+ while (prev) {
13
+ if (prev.kind === 'Name' && prev.value && queryRegex.test(prev.value)) {
14
+ return (0, graphql_1.locatedError)(validationError, validationError.nodes, [prev.value]);
15
+ }
16
+ prev = prev.prev;
17
+ }
18
+ return (0, graphql_1.locatedError)(validationError, validationError.nodes);
19
+ }
20
+ exports.addPathToValidationError = addPathToValidationError;
@@ -20,7 +20,6 @@ const env_1 = __importDefault(require("../env"));
20
20
  const exceptions_1 = require("../exceptions");
21
21
  const logger_1 = __importDefault(require("../logger"));
22
22
  const get_date_formatted_1 = require("../utils/get-date-formatted");
23
- const parse_json_1 = require("../utils/parse-json");
24
23
  const files_1 = require("./files");
25
24
  const items_1 = require("./items");
26
25
  const notifications_1 = require("./notifications");
@@ -31,12 +30,12 @@ class ImportService {
31
30
  this.schema = options.schema;
32
31
  }
33
32
  async import(collection, mimetype, stream) {
34
- var _a, _b, _c, _d, _e;
35
- if (collection.startsWith('directus_'))
33
+ var _a, _b, _c, _d, _e, _f;
34
+ if (((_a = this.accountability) === null || _a === void 0 ? void 0 : _a.admin) !== true && collection.startsWith('directus_'))
36
35
  throw new exceptions_1.ForbiddenException();
37
- const createPermissions = (_b = (_a = this.accountability) === null || _a === void 0 ? void 0 : _a.permissions) === null || _b === void 0 ? void 0 : _b.find((permission) => permission.collection === collection && permission.action === 'create');
38
- const updatePermissions = (_d = (_c = this.accountability) === null || _c === void 0 ? void 0 : _c.permissions) === null || _d === void 0 ? void 0 : _d.find((permission) => permission.collection === collection && permission.action === 'update');
39
- if (((_e = this.accountability) === null || _e === void 0 ? void 0 : _e.admin) !== true && (!createPermissions || !updatePermissions)) {
36
+ const createPermissions = (_c = (_b = this.accountability) === null || _b === void 0 ? void 0 : _b.permissions) === null || _c === void 0 ? void 0 : _c.find((permission) => permission.collection === collection && permission.action === 'create');
37
+ const updatePermissions = (_e = (_d = this.accountability) === null || _d === void 0 ? void 0 : _d.permissions) === null || _e === void 0 ? void 0 : _e.find((permission) => permission.collection === collection && permission.action === 'update');
38
+ if (((_f = this.accountability) === null || _f === void 0 ? void 0 : _f.admin) !== true && (!createPermissions || !updatePermissions)) {
40
39
  throw new exceptions_1.ForbiddenException();
41
40
  }
42
41
  switch (mimetype) {
@@ -102,7 +101,7 @@ class ImportService {
102
101
  }
103
102
  else {
104
103
  try {
105
- const parsedJson = (0, parse_json_1.parseJSON)(value);
104
+ const parsedJson = (0, utils_1.parseJSON)(value);
106
105
  (0, lodash_1.set)(result, key, parsedJson);
107
106
  }
108
107
  catch {
@@ -169,7 +168,7 @@ class ExportService {
169
168
  const requestedLimit = (_a = query.limit) !== null && _a !== void 0 ? _a : -1;
170
169
  const batchesRequired = Math.ceil(count / env_1.default.EXPORT_BATCH_SIZE);
171
170
  let readCount = 0;
172
- for (let batch = 0; batch <= batchesRequired; batch++) {
171
+ for (let batch = 0; batch < batchesRequired; batch++) {
173
172
  let limit = env_1.default.EXPORT_BATCH_SIZE;
174
173
  if (requestedLimit > 0 && env_1.default.EXPORT_BATCH_SIZE > requestedLimit - readCount) {
175
174
  limit = requestedLimit - readCount;
@@ -177,7 +176,7 @@ class ExportService {
177
176
  const result = await service.readByQuery({
178
177
  ...query,
179
178
  limit,
180
- page: batch,
179
+ offset: batch * env_1.default.EXPORT_BATCH_SIZE,
181
180
  });
182
181
  readCount += result.length;
183
182
  if (result.length) {
@@ -265,7 +264,11 @@ class ExportService {
265
264
  transforms: [json2csv_1.transforms.flatten({ separator: '.' })],
266
265
  header: (options === null || options === void 0 ? void 0 : options.includeHeader) !== false,
267
266
  });
268
- return parser.parse(input);
267
+ let string = parser.parse(input);
268
+ if ((options === null || options === void 0 ? void 0 : options.includeHeader) === false) {
269
+ string = '\n' + string;
270
+ }
271
+ return string;
269
272
  }
270
273
  throw new exceptions_1.ServiceUnavailableException(`Illegal export type used: "${format}"`, { service: 'export' });
271
274
  }
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -44,7 +44,11 @@ export declare class ItemsService<Item extends AnyItem = AnyItem> implements Abs
44
44
  */
45
45
  updateOne(key: PrimaryKey, data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey>;
46
46
  /**
47
- * Update many items by primary key
47
+ * Update multiple items in a single transaction
48
+ */
49
+ updateBatch(data: Partial<Item>[], opts?: MutationOptions): Promise<PrimaryKey[]>;
50
+ /**
51
+ * Update many items by primary key, setting all items to the same change
48
52
  */
49
53
  updateMany(keys: PrimaryKey[], data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey[]>;
50
54
  /**