directus 9.12.1 → 9.14.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 (136) hide show
  1. package/dist/app.js +20 -5
  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 +20 -25
  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/emitter.js +12 -7
  49. package/dist/env.d.ts +1 -1
  50. package/dist/env.js +8 -3
  51. package/dist/exceptions/database/translate.js +5 -1
  52. package/dist/exceptions/index.js +5 -1
  53. package/dist/extensions.d.ts +2 -1
  54. package/dist/extensions.js +28 -20
  55. package/dist/flows.d.ts +5 -0
  56. package/dist/flows.js +66 -40
  57. package/dist/index.js +5 -1
  58. package/dist/logger.js +5 -1
  59. package/dist/messenger.js +2 -2
  60. package/dist/middleware/graphql.js +2 -2
  61. package/dist/middleware/respond.js +10 -1
  62. package/dist/middleware/validate-batch.js +3 -1
  63. package/dist/operations/item-create/index.js +1 -2
  64. package/dist/operations/item-delete/index.d.ts +1 -0
  65. package/dist/operations/item-delete/index.js +8 -7
  66. package/dist/operations/item-read/index.d.ts +1 -0
  67. package/dist/operations/item-read/index.js +8 -7
  68. package/dist/operations/item-update/index.d.ts +1 -0
  69. package/dist/operations/item-update/index.js +9 -8
  70. package/dist/operations/log/index.js +1 -2
  71. package/dist/operations/notification/index.js +1 -2
  72. package/dist/operations/request/index.d.ts +4 -1
  73. package/dist/operations/request/index.js +5 -1
  74. package/dist/operations/transform/index.js +1 -2
  75. package/dist/operations/trigger/index.js +1 -2
  76. package/dist/server.js +5 -1
  77. package/dist/services/assets.js +5 -1
  78. package/dist/services/collections.js +5 -1
  79. package/dist/services/fields.d.ts +3 -3
  80. package/dist/services/fields.js +25 -17
  81. package/dist/services/files.js +5 -1
  82. package/dist/services/flows.d.ts +1 -2
  83. package/dist/services/flows.js +19 -8
  84. package/dist/services/{graphql.d.ts → graphql/index.d.ts} +3 -5
  85. package/dist/services/{graphql.js → graphql/index.js} +109 -101
  86. package/dist/services/graphql/types/date.d.ts +2 -0
  87. package/dist/services/graphql/types/date.js +9 -0
  88. package/dist/services/graphql/types/geojson.d.ts +2 -0
  89. package/dist/services/graphql/types/geojson.js +10 -0
  90. package/dist/services/graphql/types/string-or-float.d.ts +5 -0
  91. package/dist/services/graphql/types/string-or-float.js +34 -0
  92. package/dist/services/graphql/types/void.d.ts +2 -0
  93. package/dist/services/graphql/types/void.js +17 -0
  94. package/dist/services/graphql/utils/add-path-to-validation-error.d.ts +2 -0
  95. package/dist/services/graphql/utils/add-path-to-validation-error.js +20 -0
  96. package/dist/services/import-export.js +12 -8
  97. package/dist/services/index.js +5 -1
  98. package/dist/services/items.d.ts +6 -1
  99. package/dist/services/items.js +43 -19
  100. package/dist/services/mail/index.js +8 -6
  101. package/dist/services/notifications.js +22 -11
  102. package/dist/services/operations.d.ts +1 -2
  103. package/dist/services/operations.js +19 -8
  104. package/dist/services/payload.js +13 -11
  105. package/dist/services/permissions.d.ts +1 -0
  106. package/dist/services/permissions.js +5 -0
  107. package/dist/services/relations.js +5 -1
  108. package/dist/services/roles.d.ts +1 -0
  109. package/dist/services/roles.js +9 -0
  110. package/dist/services/server.js +5 -1
  111. package/dist/services/users.d.ts +1 -0
  112. package/dist/services/users.js +22 -0
  113. package/dist/types/index.js +5 -1
  114. package/dist/utils/apply-query.js +24 -15
  115. package/dist/utils/apply-snapshot.js +3 -0
  116. package/dist/utils/calculate-field-depth.d.ts +33 -0
  117. package/dist/utils/calculate-field-depth.js +75 -0
  118. package/dist/utils/get-column.js +1 -1
  119. package/dist/utils/get-default-value.js +3 -13
  120. package/dist/utils/get-graphql-type.js +4 -3
  121. package/dist/utils/get-local-type.d.ts +6 -3
  122. package/dist/utils/get-permissions.js +3 -4
  123. package/dist/utils/get-schema.js +1 -2
  124. package/dist/utils/get-string-byte-size.d.ts +4 -0
  125. package/dist/utils/get-string-byte-size.js +10 -0
  126. package/dist/utils/job-queue.d.ts +9 -0
  127. package/dist/utils/job-queue.js +24 -0
  128. package/dist/utils/jwt.js +5 -1
  129. package/dist/utils/sanitize-query.js +4 -5
  130. package/dist/utils/validate-query.js +50 -0
  131. package/dist/webhooks.js +5 -1
  132. package/package.json +74 -73
  133. package/dist/utils/operation-options.d.ts +0 -3
  134. package/dist/utils/operation-options.js +0 -45
  135. package/dist/utils/parse-json.d.ts +0 -5
  136. package/dist/utils/parse-json.js +0 -19
package/dist/app.js CHANGED
@@ -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];
@@ -72,6 +76,7 @@ const extract_token_1 = __importDefault(require("./middleware/extract-token"));
72
76
  const rate_limiter_1 = __importDefault(require("./middleware/rate-limiter"));
73
77
  const sanitize_query_1 = __importDefault(require("./middleware/sanitize-query"));
74
78
  const schema_1 = __importDefault(require("./middleware/schema"));
79
+ const constants_1 = require("./constants");
75
80
  const track_1 = require("./utils/track");
76
81
  const validate_env_1 = require("./utils/validate-env");
77
82
  const validate_storage_1 = require("./utils/validate-storage");
@@ -157,19 +162,29 @@ async function createApp() {
157
162
  next();
158
163
  }
159
164
  });
165
+ app.get('/robots.txt', (_, res) => {
166
+ res.set('Content-Type', 'text/plain');
167
+ res.status(200);
168
+ res.send(constants_1.ROBOTSTXT);
169
+ });
160
170
  if (env_1.default.SERVE_APP) {
161
171
  const adminPath = require.resolve('@directus/app');
162
172
  const adminUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('admin');
163
173
  // Set the App's base path according to the APIs public URL
164
174
  const html = await fs_extra_1.default.readFile(adminPath, 'utf8');
165
175
  const htmlWithBase = html.replace(/<base \/>/, `<base href="${adminUrl.toString({ rootRelative: true })}/" />`);
166
- const noCacheIndexHtmlHandler = (_req, res) => {
176
+ const sendHtml = (_req, res) => {
167
177
  res.setHeader('Cache-Control', 'no-cache');
178
+ res.setHeader('Vary', 'Origin, Cache-Control');
168
179
  res.send(htmlWithBase);
169
180
  };
170
- app.get('/admin', noCacheIndexHtmlHandler);
171
- app.use('/admin', express_1.default.static(path_1.default.join(adminPath, '..')));
172
- app.use('/admin/*', noCacheIndexHtmlHandler);
181
+ const setStaticHeaders = (res) => {
182
+ res.setHeader('Cache-Control', 'max-age=31536000, immutable');
183
+ res.setHeader('Vary', 'Origin, Cache-Control');
184
+ };
185
+ app.get('/admin', sendHtml);
186
+ app.use('/admin', express_1.default.static(path_1.default.join(adminPath, '..'), { setHeaders: setStaticHeaders }));
187
+ app.use('/admin/*', sendHtml);
173
188
  }
174
189
  // use the rate limiter - all routes for now
175
190
  if (env_1.default.RATE_LIMITER_ENABLED === true) {
@@ -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];
@@ -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];
@@ -4,6 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createOAuth2AuthRouter = exports.OAuth2AuthDriver = void 0;
7
+ const exceptions_1 = require("@directus/shared/exceptions");
8
+ const utils_1 = require("@directus/shared/utils");
7
9
  const express_1 = require("express");
8
10
  const flat_1 = __importDefault(require("flat"));
9
11
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
@@ -11,14 +13,13 @@ const ms_1 = __importDefault(require("ms"));
11
13
  const openid_client_1 = require("openid-client");
12
14
  const auth_1 = require("../../auth");
13
15
  const env_1 = __importDefault(require("../../env"));
14
- const exceptions_1 = require("../../exceptions");
16
+ const exceptions_2 = require("../../exceptions");
15
17
  const logger_1 = __importDefault(require("../../logger"));
16
18
  const respond_1 = require("../../middleware/respond");
17
19
  const services_1 = require("../../services");
18
20
  const async_handler_1 = __importDefault(require("../../utils/async-handler"));
19
21
  const get_config_from_env_1 = require("../../utils/get-config-from-env");
20
22
  const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
21
- const parse_json_1 = require("../../utils/parse-json");
22
23
  const url_1 = require("../../utils/url");
23
24
  const local_1 = require("./local");
24
25
  class OAuth2AuthDriver extends local_1.LocalAuthDriver {
@@ -26,7 +27,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
26
27
  super(options, config);
27
28
  const { authorizeUrl, accessUrl, profileUrl, clientId, clientSecret, ...additionalConfig } = config;
28
29
  if (!authorizeUrl || !accessUrl || !profileUrl || !clientId || !clientSecret || !additionalConfig.provider) {
29
- throw new exceptions_1.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
30
+ throw new exceptions_2.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
30
31
  }
31
32
  const redirectUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('auth', 'login', additionalConfig.provider, 'callback');
32
33
  this.redirectUrl = redirectUrl.toString();
@@ -81,7 +82,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
81
82
  async getUserID(payload) {
82
83
  if (!payload.code || !payload.codeVerifier) {
83
84
  logger_1.default.trace('[OAuth2] No code or codeVerifier in payload');
84
- throw new exceptions_1.InvalidCredentialsException();
85
+ throw new exceptions_2.InvalidCredentialsException();
85
86
  }
86
87
  let tokenSet;
87
88
  let userInfo;
@@ -100,7 +101,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
100
101
  const identifier = userInfo[identifierKey] ? String(userInfo[identifierKey]) : email;
101
102
  if (!identifier) {
102
103
  logger_1.default.warn(`[OAuth2] Failed to find user identifier for provider "${provider}"`);
103
- throw new exceptions_1.InvalidCredentialsException();
104
+ throw new exceptions_2.InvalidCredentialsException();
104
105
  }
105
106
  const userId = await this.fetchUserId(identifier);
106
107
  if (userId) {
@@ -115,7 +116,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
115
116
  // Is public registration allowed?
116
117
  if (!allowPublicRegistration) {
117
118
  logger_1.default.trace(`[OAuth2] User doesn't exist, and public registration not allowed for provider "${provider}"`);
118
- throw new exceptions_1.InvalidCredentialsException();
119
+ throw new exceptions_2.InvalidCredentialsException();
119
120
  }
120
121
  await this.usersService.createOne({
121
122
  provider,
@@ -135,7 +136,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
135
136
  let authData = user.auth_data;
136
137
  if (typeof authData === 'string') {
137
138
  try {
138
- authData = (0, parse_json_1.parseJSON)(authData);
139
+ authData = (0, utils_1.parseJSON)(authData);
139
140
  }
140
141
  catch {
141
142
  logger_1.default.warn(`[OAuth2] Session data isn't valid JSON: ${authData}`);
@@ -163,11 +164,11 @@ const handleError = (e) => {
163
164
  if (e.error === 'invalid_grant') {
164
165
  // Invalid token
165
166
  logger_1.default.trace(e, `[OAuth2] Invalid grant`);
166
- return new exceptions_1.InvalidTokenException();
167
+ return new exceptions_2.InvalidTokenException();
167
168
  }
168
169
  // Server response error
169
170
  logger_1.default.trace(e, `[OAuth2] Unknown OP error`);
170
- return new exceptions_1.ServiceUnavailableException('Service returned unexpected response', {
171
+ return new exceptions_2.ServiceUnavailableException('Service returned unexpected response', {
171
172
  service: 'oauth2',
172
173
  message: e.error_description,
173
174
  });
@@ -175,7 +176,7 @@ const handleError = (e) => {
175
176
  else if (e instanceof openid_client_1.errors.RPError) {
176
177
  // Internal client error
177
178
  logger_1.default.trace(e, `[OAuth2] Unknown RP error`);
178
- return new exceptions_1.InvalidCredentialsException();
179
+ return new exceptions_2.InvalidCredentialsException();
179
180
  }
180
181
  logger_1.default.trace(e, `[OAuth2] Unknown error`);
181
182
  return e;
@@ -204,7 +205,7 @@ function createOAuth2AuthRouter(providerName) {
204
205
  }
205
206
  catch (e) {
206
207
  logger_1.default.warn(e, `[OAuth2] Couldn't verify OAuth2 cookie`);
207
- throw new exceptions_1.InvalidCredentialsException();
208
+ throw new exceptions_2.InvalidCredentialsException();
208
209
  }
209
210
  const { verifier, redirect, prompt } = tokenData;
210
211
  const authenticationService = new services_1.AuthenticationService({
@@ -229,22 +230,13 @@ function createOAuth2AuthRouter(providerName) {
229
230
  }
230
231
  catch (error) {
231
232
  // Prompt user for a new refresh_token if invalidated
232
- if (error instanceof exceptions_1.InvalidTokenException && !prompt) {
233
+ if (error instanceof exceptions_2.InvalidTokenException && !prompt) {
233
234
  return res.redirect(`./?${redirect ? `redirect=${redirect}&` : ''}prompt=true`);
234
235
  }
235
236
  if (redirect) {
236
237
  let reason = 'UNKNOWN_EXCEPTION';
237
- if (error instanceof exceptions_1.ServiceUnavailableException) {
238
- reason = 'SERVICE_UNAVAILABLE';
239
- }
240
- else if (error instanceof exceptions_1.InvalidCredentialsException) {
241
- reason = 'INVALID_USER';
242
- }
243
- else if (error instanceof exceptions_1.InvalidTokenException) {
244
- reason = 'INVALID_TOKEN';
245
- }
246
- else if (error instanceof exceptions_1.InvalidProviderException) {
247
- reason = 'INVALID_PROVIDER';
238
+ if (error instanceof exceptions_1.BaseException) {
239
+ reason = error.code;
248
240
  }
249
241
  else {
250
242
  logger_1.default.warn(error, `[OAuth2] Unexpected error during OAuth2 login`);
@@ -4,6 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createOpenIDAuthRouter = exports.OpenIDAuthDriver = void 0;
7
+ const exceptions_1 = require("@directus/shared/exceptions");
8
+ const utils_1 = require("@directus/shared/utils");
7
9
  const express_1 = require("express");
8
10
  const flat_1 = __importDefault(require("flat"));
9
11
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
@@ -11,14 +13,13 @@ const ms_1 = __importDefault(require("ms"));
11
13
  const openid_client_1 = require("openid-client");
12
14
  const auth_1 = require("../../auth");
13
15
  const env_1 = __importDefault(require("../../env"));
14
- const exceptions_1 = require("../../exceptions");
16
+ const exceptions_2 = require("../../exceptions");
15
17
  const logger_1 = __importDefault(require("../../logger"));
16
18
  const respond_1 = require("../../middleware/respond");
17
19
  const services_1 = require("../../services");
18
20
  const async_handler_1 = __importDefault(require("../../utils/async-handler"));
19
21
  const get_config_from_env_1 = require("../../utils/get-config-from-env");
20
22
  const get_ip_from_req_1 = require("../../utils/get-ip-from-req");
21
- const parse_json_1 = require("../../utils/parse-json");
22
23
  const url_1 = require("../../utils/url");
23
24
  const local_1 = require("./local");
24
25
  class OpenIDAuthDriver extends local_1.LocalAuthDriver {
@@ -26,7 +27,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
26
27
  super(options, config);
27
28
  const { issuerUrl, clientId, clientSecret, ...additionalConfig } = config;
28
29
  if (!issuerUrl || !clientId || !clientSecret || !additionalConfig.provider) {
29
- throw new exceptions_1.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
30
+ throw new exceptions_2.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
30
31
  }
31
32
  const redirectUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('auth', 'login', additionalConfig.provider, 'callback');
32
33
  const clientOptionsOverrides = (0, get_config_from_env_1.getConfigFromEnv)(`AUTH_${config.provider.toUpperCase()}_CLIENT_`, [`AUTH_${config.provider.toUpperCase()}_CLIENT_ID`, `AUTH_${config.provider.toUpperCase()}_CLIENT_SECRET`], 'underscore');
@@ -38,7 +39,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
38
39
  .then((issuer) => {
39
40
  const supportedTypes = issuer.metadata.response_types_supported;
40
41
  if (!(supportedTypes === null || supportedTypes === void 0 ? void 0 : supportedTypes.includes('code'))) {
41
- reject(new exceptions_1.InvalidConfigException('OpenID provider does not support required code flow', {
42
+ reject(new exceptions_2.InvalidConfigException('OpenID provider does not support required code flow', {
42
43
  provider: additionalConfig.provider,
43
44
  }));
44
45
  }
@@ -50,7 +51,10 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
50
51
  ...clientOptionsOverrides,
51
52
  }));
52
53
  })
53
- .catch(reject);
54
+ .catch((e) => {
55
+ logger_1.default.error(e, '[OpenID] Failed to fetch provider config');
56
+ process.exit(1);
57
+ });
54
58
  });
55
59
  }
56
60
  generateCodeVerifier() {
@@ -88,7 +92,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
88
92
  async getUserID(payload) {
89
93
  if (!payload.code || !payload.codeVerifier) {
90
94
  logger_1.default.trace('[OpenID] No code or codeVerifier in payload');
91
- throw new exceptions_1.InvalidCredentialsException();
95
+ throw new exceptions_2.InvalidCredentialsException();
92
96
  }
93
97
  let tokenSet;
94
98
  let userInfo;
@@ -114,7 +118,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
114
118
  const identifier = userInfo[identifierKey !== null && identifierKey !== void 0 ? identifierKey : 'sub'] ? String(userInfo[identifierKey !== null && identifierKey !== void 0 ? identifierKey : 'sub']) : email;
115
119
  if (!identifier) {
116
120
  logger_1.default.warn(`[OpenID] Failed to find user identifier for provider "${provider}"`);
117
- throw new exceptions_1.InvalidCredentialsException();
121
+ throw new exceptions_2.InvalidCredentialsException();
118
122
  }
119
123
  const userId = await this.fetchUserId(identifier);
120
124
  if (userId) {
@@ -130,7 +134,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
130
134
  // Is public registration allowed?
131
135
  if (!allowPublicRegistration || !isEmailVerified) {
132
136
  logger_1.default.trace(`[OpenID] User doesn't exist, and public registration not allowed for provider "${provider}"`);
133
- throw new exceptions_1.InvalidCredentialsException();
137
+ throw new exceptions_2.InvalidCredentialsException();
134
138
  }
135
139
  await this.usersService.createOne({
136
140
  provider,
@@ -150,7 +154,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
150
154
  let authData = user.auth_data;
151
155
  if (typeof authData === 'string') {
152
156
  try {
153
- authData = (0, parse_json_1.parseJSON)(authData);
157
+ authData = (0, utils_1.parseJSON)(authData);
154
158
  }
155
159
  catch {
156
160
  logger_1.default.warn(`[OpenID] Session data isn't valid JSON: ${authData}`);
@@ -179,11 +183,11 @@ const handleError = (e) => {
179
183
  if (e.error === 'invalid_grant') {
180
184
  // Invalid token
181
185
  logger_1.default.trace(e, `[OpenID] Invalid grant`);
182
- return new exceptions_1.InvalidTokenException();
186
+ return new exceptions_2.InvalidTokenException();
183
187
  }
184
188
  // Server response error
185
189
  logger_1.default.trace(e, `[OpenID] Unknown OP error`);
186
- return new exceptions_1.ServiceUnavailableException('Service returned unexpected response', {
190
+ return new exceptions_2.ServiceUnavailableException('Service returned unexpected response', {
187
191
  service: 'openid',
188
192
  message: e.error_description,
189
193
  });
@@ -191,7 +195,7 @@ const handleError = (e) => {
191
195
  else if (e instanceof openid_client_1.errors.RPError) {
192
196
  // Internal client error
193
197
  logger_1.default.trace(e, `[OpenID] Unknown RP error`);
194
- return new exceptions_1.InvalidCredentialsException();
198
+ return new exceptions_2.InvalidCredentialsException();
195
199
  }
196
200
  logger_1.default.trace(e, `[OpenID] Unknown error`);
197
201
  return e;
@@ -220,7 +224,7 @@ function createOpenIDAuthRouter(providerName) {
220
224
  }
221
225
  catch (e) {
222
226
  logger_1.default.warn(e, `[OpenID] Couldn't verify OpenID cookie`);
223
- throw new exceptions_1.InvalidCredentialsException();
227
+ throw new exceptions_2.InvalidCredentialsException();
224
228
  }
225
229
  const { verifier, redirect, prompt } = tokenData;
226
230
  const authenticationService = new services_1.AuthenticationService({
@@ -245,23 +249,14 @@ function createOpenIDAuthRouter(providerName) {
245
249
  }
246
250
  catch (error) {
247
251
  // Prompt user for a new refresh_token if invalidated
248
- if (error instanceof exceptions_1.InvalidTokenException && !prompt) {
252
+ if (error instanceof exceptions_2.InvalidTokenException && !prompt) {
249
253
  return res.redirect(`./?${redirect ? `redirect=${redirect}&` : ''}prompt=true`);
250
254
  }
251
255
  logger_1.default.warn(error);
252
256
  if (redirect) {
253
257
  let reason = 'UNKNOWN_EXCEPTION';
254
- if (error instanceof exceptions_1.ServiceUnavailableException) {
255
- reason = 'SERVICE_UNAVAILABLE';
256
- }
257
- else if (error instanceof exceptions_1.InvalidCredentialsException) {
258
- reason = 'INVALID_USER';
259
- }
260
- else if (error instanceof exceptions_1.InvalidTokenException) {
261
- reason = 'INVALID_TOKEN';
262
- }
263
- else if (error instanceof exceptions_1.InvalidProviderException) {
264
- reason = 'INVALID_PROVIDER';
258
+ if (error instanceof exceptions_1.BaseException) {
259
+ reason = error.code;
265
260
  }
266
261
  else {
267
262
  logger_1.default.warn(error, `[OpenID] Unexpected error during OpenID login`);
@@ -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];
@@ -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];
@@ -23,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
23
27
  };
24
28
  Object.defineProperty(exports, "__esModule", { value: true });
25
29
  exports.apply = void 0;
30
+ const utils_1 = require("@directus/shared/utils");
26
31
  const chalk_1 = __importDefault(require("chalk"));
27
32
  const fs_1 = require("fs");
28
33
  const inquirer_1 = __importDefault(require("inquirer"));
@@ -34,7 +39,6 @@ const logger_1 = __importDefault(require("../../../logger"));
34
39
  const apply_snapshot_1 = require("../../../utils/apply-snapshot");
35
40
  const get_snapshot_1 = require("../../../utils/get-snapshot");
36
41
  const get_snapshot_diff_1 = require("../../../utils/get-snapshot-diff");
37
- const parse_json_1 = require("../../../utils/parse-json");
38
42
  async function apply(snapshotPath, options) {
39
43
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
40
44
  const filename = path_1.default.resolve(process.cwd(), snapshotPath);
@@ -53,7 +57,7 @@ async function apply(snapshotPath, options) {
53
57
  snapshot = (await (0, js_yaml_1.load)(fileContents));
54
58
  }
55
59
  else {
56
- snapshot = (0, parse_json_1.parseJSON)(fileContents);
60
+ snapshot = (0, utils_1.parseJSON)(fileContents);
57
61
  }
58
62
  const currentSnapshot = await (0, get_snapshot_1.getSnapshot)({ database });
59
63
  const snapshotDiff = (0, get_snapshot_diff_1.getSnapshotDiff)(currentSnapshot, snapshot);
@@ -1,4 +1,4 @@
1
- export declare function snapshot(snapshotPath: string, options?: {
1
+ export declare function snapshot(snapshotPath?: string, options?: {
2
2
  yes: boolean;
3
3
  format: 'json' | 'yaml';
4
4
  }): Promise<void>;
@@ -13,38 +13,46 @@ const inquirer_1 = __importDefault(require("inquirer"));
13
13
  const js_yaml_1 = require("js-yaml");
14
14
  const cache_1 = require("../../../cache");
15
15
  async function snapshot(snapshotPath, options) {
16
- const filename = path_1.default.resolve(process.cwd(), snapshotPath);
17
- let snapshotExists;
18
- try {
19
- await fs_1.promises.access(filename, fs_1.constants.F_OK);
20
- snapshotExists = true;
21
- }
22
- catch {
23
- snapshotExists = false;
24
- }
25
- if (snapshotExists && (options === null || options === void 0 ? void 0 : options.yes) === false) {
26
- const { overwrite } = await inquirer_1.default.prompt([
27
- {
28
- type: 'confirm',
29
- name: 'overwrite',
30
- message: 'Snapshot already exists. Do you want to overwrite the file?',
31
- },
32
- ]);
33
- if (overwrite === false) {
34
- process.exit(0);
35
- }
36
- }
37
16
  await (0, cache_1.flushCaches)();
38
17
  const database = (0, database_1.default)();
39
- const snapshot = await (0, get_snapshot_1.getSnapshot)({ database });
40
18
  try {
19
+ const snapshot = await (0, get_snapshot_1.getSnapshot)({ database });
20
+ let snapshotString;
41
21
  if ((options === null || options === void 0 ? void 0 : options.format) === 'yaml') {
42
- await fs_1.promises.writeFile(filename, (0, js_yaml_1.dump)(snapshot));
22
+ snapshotString = (0, js_yaml_1.dump)(snapshot);
23
+ }
24
+ else {
25
+ snapshotString = JSON.stringify(snapshot);
26
+ }
27
+ if (snapshotPath) {
28
+ const filename = path_1.default.resolve(process.cwd(), snapshotPath);
29
+ let snapshotExists;
30
+ try {
31
+ await fs_1.promises.access(filename, fs_1.constants.F_OK);
32
+ snapshotExists = true;
33
+ }
34
+ catch {
35
+ snapshotExists = false;
36
+ }
37
+ if (snapshotExists && (options === null || options === void 0 ? void 0 : options.yes) === false) {
38
+ const { overwrite } = await inquirer_1.default.prompt([
39
+ {
40
+ type: 'confirm',
41
+ name: 'overwrite',
42
+ message: 'Snapshot already exists. Do you want to overwrite the file?',
43
+ },
44
+ ]);
45
+ if (overwrite === false) {
46
+ database.destroy();
47
+ process.exit(0);
48
+ }
49
+ }
50
+ await fs_1.promises.writeFile(filename, snapshotString);
51
+ logger_1.default.info(`Snapshot saved to ${filename}`);
43
52
  }
44
53
  else {
45
- await fs_1.promises.writeFile(filename, JSON.stringify(snapshot));
54
+ process.stdout.write(snapshotString);
46
55
  }
47
- logger_1.default.info(`Snapshot saved to ${filename}`);
48
56
  database.destroy();
49
57
  process.exit(0);
50
58
  }
package/dist/cli/index.js CHANGED
@@ -75,7 +75,7 @@ async function createCli() {
75
75
  .description('Create a new Schema Snapshot')
76
76
  .option('-y, --yes', `Assume "yes" as answer to all prompts and run non-interactively`, false)
77
77
  .addOption(new commander_1.Option('--format <format>', 'JSON or YAML format').choices(['json', 'yaml']).default('yaml'))
78
- .argument('<path>', 'Path to snapshot file')
78
+ .argument('[path]', 'Path to snapshot file')
79
79
  .action(snapshot_1.snapshot);
80
80
  schemaCommands
81
81
  .command('apply')
@@ -1,12 +1,12 @@
1
1
  ####################################################################################################
2
- #
2
+ #
3
3
  # These values set environment variables which modify core settings of Directus.
4
4
  #
5
5
  # Values in square brackets are the default values.
6
6
  #
7
- # The following options are not all possible options. For more, see
8
- # https://docs.directus.io/configuration/config-options/
9
- #
7
+ # The following options are not all possible options. For more, see
8
+ # https://docs.directus.io/self-hosted/config-options/
9
+ #
10
10
  ####################################################################################################
11
11
  ####################################################################################################
12
12
 
@@ -18,7 +18,7 @@ HOST="0.0.0.0"
18
18
  # The port Directus will run on [8055]
19
19
  PORT=8055
20
20
 
21
- # The URL where your API can be reached on the web. It is also used for things like OAuth redirects,
21
+ # The URL where your API can be reached on the web. It is also used for things like OAuth redirects,
22
22
  # forgot-password emails, and logos that needs to be publicly available on the internet. ["/"]
23
23
  PUBLIC_URL="/"
24
24
  # PUBLIC_URL="http://localhost:8055"
@@ -46,8 +46,8 @@ PUBLIC_URL="/"
46
46
  ####################################################################################################
47
47
  ### Database
48
48
 
49
- # All DB_* environment variables are passed to the connection configuration of a Knex instance.
50
- # Based on your project's needs, you can extend the DB_* environment variables with any config
49
+ # All DB_* environment variables are passed to the connection configuration of a Knex instance.
50
+ # Based on your project's needs, you can extend the DB_* environment variables with any config
51
51
  # you need to pass to the database instance.
52
52
 
53
53
  {{ database }}
@@ -177,7 +177,7 @@ STORAGE_LOCAL_ROOT="./uploads"
177
177
  # STORAGE_GOOGLE_BUCKET="my-files"
178
178
 
179
179
 
180
- ## A comma-separated list of metadata keys to collect during file upload. Use * for all
180
+ ## A comma-separated list of metadata keys to collect during file upload. Use * for all
181
181
  # Extracting all metadata might cause memory issues when the file has an unusually large set of metadata
182
182
  # [ifd0.Make,ifd0.Model,exif.FNumber,exif.ExposureTime,exif.FocalLength,exif.ISO]
183
183
  # FILE_METADATA_ALLOW_LIST=
@@ -190,7 +190,7 @@ STORAGE_LOCAL_ROOT="./uploads"
190
190
  # Unique identifier for the project
191
191
  # KEY="xxxxxxx-xxxxxx-xxxxxxxx-xxxxxxxxxx"
192
192
 
193
- # Secret string for the project
193
+ # Secret string for the project
194
194
  # SECRET="abcdef"
195
195
 
196
196
  # The duration that the access token is valid ["15m"]
@@ -250,7 +250,7 @@ CORS_MAX_AGE=18000
250
250
  # The variant of the hash function (0: argon2d, 1: argon2i, or 2: argon2id) [1]
251
251
  # HASH_TYPE=2
252
252
 
253
- An extra and optional non-secret value. The value will be included B64 encoded in the parameters portion of the digest []
253
+ # An extra and optional non-secret value. The value will be included B64 encoded in the parameters portion of the digest []
254
254
  # HASH_ASSOCIATED_DATA=foo
255
255
 
256
256
  ####################################################################################################
@@ -287,7 +287,7 @@ EXTENSIONS_AUTO_RELOAD=false
287
287
  # Email address from which emails are sent ["no-reply@directus.io"]
288
288
  EMAIL_FROM="no-reply@directus.io"
289
289
 
290
- # What to use to send emails. One of
290
+ # What to use to send emails. One of
291
291
  # sendmail, smtp, mailgun, ses.
292
292
  EMAIL_TRANSPORT="sendmail"
293
293
  EMAIL_SENDMAIL_NEW_LINE="unix"
@@ -13,3 +13,4 @@ export declare const COOKIE_OPTIONS: {
13
13
  secure: any;
14
14
  sameSite: "lax" | "strict" | "none";
15
15
  };
16
+ export declare const ROBOTSTXT: string;
package/dist/constants.js CHANGED
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  var _a;
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.COOKIE_OPTIONS = exports.UUID_REGEX = exports.COLUMN_TRANSFORMS = exports.DEFAULT_AUTH_PROVIDER = exports.ALIAS_TYPES = exports.FILTER_VARIABLES = exports.ASSET_TRANSFORM_QUERY_KEYS = exports.SYSTEM_ASSET_ALLOW_LIST = void 0;
7
+ exports.ROBOTSTXT = exports.COOKIE_OPTIONS = exports.UUID_REGEX = exports.COLUMN_TRANSFORMS = exports.DEFAULT_AUTH_PROVIDER = exports.ALIAS_TYPES = exports.FILTER_VARIABLES = exports.ASSET_TRANSFORM_QUERY_KEYS = exports.SYSTEM_ASSET_ALLOW_LIST = void 0;
8
8
  const env_1 = __importDefault(require("./env"));
9
9
  const ms_1 = __importDefault(require("ms"));
10
10
  exports.SYSTEM_ASSET_ALLOW_LIST = [
@@ -55,3 +55,7 @@ exports.COOKIE_OPTIONS = {
55
55
  secure: (_a = env_1.default.REFRESH_TOKEN_COOKIE_SECURE) !== null && _a !== void 0 ? _a : false,
56
56
  sameSite: env_1.default.REFRESH_TOKEN_COOKIE_SAME_SITE || 'strict',
57
57
  };
58
+ exports.ROBOTSTXT = `
59
+ User-agent: *
60
+ Disallow: /
61
+ `.trim();
@@ -3,6 +3,7 @@ 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
+ const utils_1 = require("@directus/shared/utils");
6
7
  const express_1 = require("express");
7
8
  const helmet_1 = __importDefault(require("helmet"));
8
9
  const lodash_1 = require("lodash");
@@ -16,10 +17,9 @@ const services_1 = require("../services");
16
17
  const assets_1 = require("../types/assets");
17
18
  const async_handler_1 = __importDefault(require("../utils/async-handler"));
18
19
  const get_config_from_env_1 = require("../utils/get-config-from-env");
19
- const parse_json_1 = require("../utils/parse-json");
20
20
  const router = (0, express_1.Router)();
21
21
  router.use((0, use_collection_1.default)('directus_files'));
22
- router.get('/:pk',
22
+ router.get('/:pk/:filename?',
23
23
  // Validate query params
24
24
  (0, async_handler_1.default)(async (req, res, next) => {
25
25
  const payloadService = new services_1.PayloadService('directus_settings', { schema: req.schema });
@@ -41,7 +41,7 @@ router.get('/:pk',
41
41
  let transforms;
42
42
  // Try parse the JSON array
43
43
  try {
44
- transforms = (0, parse_json_1.parseJSON)(transformation['transforms']);
44
+ transforms = (0, utils_1.parseJSON)(transformation['transforms']);
45
45
  }
46
46
  catch {
47
47
  throw new exceptions_1.InvalidQueryException(`"transforms" Parameter needs to be a JSON array of allowed transformations.`);
@@ -99,7 +99,7 @@ router.get('/:pk',
99
99
  }, (0, get_config_from_env_1.getConfigFromEnv)('ASSETS_CONTENT_SECURITY_POLICY'))),
100
100
  // Return file
101
101
  (0, async_handler_1.default)(async (req, res) => {
102
- var _a, _b;
102
+ var _a, _b, _c;
103
103
  const id = (_a = req.params.pk) === null || _a === void 0 ? void 0 : _a.substring(0, 36);
104
104
  const service = new services_1.AssetsService({
105
105
  accountability: req.accountability,
@@ -121,7 +121,7 @@ router.get('/:pk',
121
121
  }
122
122
  const { stream, file, stat } = await service.getAsset(id, transformation, range);
123
123
  const access = ((_b = req.accountability) === null || _b === void 0 ? void 0 : _b.role) ? 'private' : 'public';
124
- res.attachment(file.filename_download);
124
+ res.attachment((_c = req.params.filename) !== null && _c !== void 0 ? _c : file.filename_download);
125
125
  res.setHeader('Content-Type', file.type);
126
126
  res.setHeader('Accept-Ranges', 'bytes');
127
127
  res.setHeader('Cache-Control', `${access}, max-age=${(0, ms_1.default)(env_1.default.ASSETS_CACHE_TTL) / 1000}`);
@@ -75,7 +75,10 @@ router.patch('/', (0, validate_batch_1.validateBatch)('update'), (0, async_handl
75
75
  schema: req.schema,
76
76
  });
77
77
  let keys = [];
78
- if (req.body.keys) {
78
+ if (Array.isArray(req.body)) {
79
+ keys = await service.updateBatch(req.body);
80
+ }
81
+ else if (req.body.keys) {
79
82
  keys = await service.updateMany(req.body.keys, req.body.data);
80
83
  }
81
84
  else {