@directus/api 11.0.1 → 12.0.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 (283) hide show
  1. package/dist/app.js +3 -4
  2. package/dist/auth/auth.d.ts +4 -4
  3. package/dist/auth/auth.js +2 -2
  4. package/dist/auth/drivers/ldap.js +20 -17
  5. package/dist/auth/drivers/local.js +5 -5
  6. package/dist/auth/drivers/oauth2.js +16 -16
  7. package/dist/auth/drivers/openid.js +18 -17
  8. package/dist/auth/drivers/saml.js +6 -7
  9. package/dist/auth.js +3 -2
  10. package/dist/cache.js +3 -13
  11. package/dist/cli/utils/create-env/env-stub.liquid +5 -7
  12. package/dist/controllers/activity.js +7 -6
  13. package/dist/controllers/assets.js +25 -12
  14. package/dist/controllers/auth.js +8 -7
  15. package/dist/controllers/collections.js +4 -3
  16. package/dist/controllers/dashboards.js +5 -4
  17. package/dist/controllers/extensions.js +3 -3
  18. package/dist/controllers/fields.js +9 -8
  19. package/dist/controllers/files.js +11 -11
  20. package/dist/controllers/flows.js +5 -4
  21. package/dist/controllers/folders.js +5 -4
  22. package/dist/controllers/items.js +14 -13
  23. package/dist/controllers/not-found.js +2 -2
  24. package/dist/controllers/notifications.js +5 -4
  25. package/dist/controllers/operations.js +5 -4
  26. package/dist/controllers/panels.js +5 -4
  27. package/dist/controllers/permissions.js +5 -4
  28. package/dist/controllers/presets.js +5 -4
  29. package/dist/controllers/relations.js +6 -5
  30. package/dist/controllers/roles.js +5 -4
  31. package/dist/controllers/schema.js +8 -8
  32. package/dist/controllers/server.js +2 -2
  33. package/dist/controllers/settings.js +3 -2
  34. package/dist/controllers/shares.js +7 -6
  35. package/dist/controllers/translations.js +6 -5
  36. package/dist/controllers/users.js +22 -21
  37. package/dist/controllers/utils.js +10 -10
  38. package/dist/controllers/webhooks.js +5 -4
  39. package/dist/{exceptions/database → database/errors}/dialects/mssql.js +8 -18
  40. package/dist/{exceptions/database → database/errors}/dialects/mysql.js +9 -19
  41. package/dist/{exceptions/database → database/errors}/dialects/oracle.js +2 -2
  42. package/dist/{exceptions/database → database/errors}/dialects/postgres.js +7 -18
  43. package/dist/{exceptions/database → database/errors}/dialects/sqlite.js +7 -10
  44. package/dist/{exceptions/database → database/errors}/translate.js +1 -1
  45. package/dist/database/migrations/run.js +10 -1
  46. package/dist/emitter.d.ts +3 -2
  47. package/dist/emitter.js +12 -4
  48. package/dist/env.js +21 -17
  49. package/dist/errors/codes.d.ts +29 -0
  50. package/dist/errors/codes.js +30 -0
  51. package/dist/errors/contains-null-values.d.ts +7 -0
  52. package/dist/errors/contains-null-values.js +4 -0
  53. package/dist/errors/content-too-large.d.ts +1 -0
  54. package/dist/errors/content-too-large.js +3 -0
  55. package/dist/errors/forbidden.d.ts +1 -0
  56. package/dist/errors/forbidden.js +3 -0
  57. package/dist/errors/hit-rate-limit.d.ts +6 -0
  58. package/dist/errors/hit-rate-limit.js +8 -0
  59. package/dist/errors/illegal-asset-transformation.d.ts +4 -0
  60. package/dist/errors/illegal-asset-transformation.js +3 -0
  61. package/dist/errors/index.d.ts +28 -0
  62. package/dist/errors/index.js +28 -0
  63. package/dist/errors/invalid-credentials.d.ts +1 -0
  64. package/dist/errors/invalid-credentials.js +3 -0
  65. package/dist/errors/invalid-foreign-key.d.ts +6 -0
  66. package/dist/errors/invalid-foreign-key.js +14 -0
  67. package/dist/errors/invalid-ip.d.ts +1 -0
  68. package/dist/errors/invalid-ip.js +3 -0
  69. package/dist/errors/invalid-otp.d.ts +1 -0
  70. package/dist/errors/invalid-otp.js +3 -0
  71. package/dist/errors/invalid-payload.d.ts +5 -0
  72. package/dist/errors/invalid-payload.js +4 -0
  73. package/dist/errors/invalid-provider-config.d.ts +5 -0
  74. package/dist/errors/invalid-provider-config.js +3 -0
  75. package/dist/errors/invalid-provider.d.ts +1 -0
  76. package/dist/errors/invalid-provider.js +3 -0
  77. package/dist/errors/invalid-query.d.ts +5 -0
  78. package/dist/errors/invalid-query.js +4 -0
  79. package/dist/errors/invalid-token.d.ts +1 -0
  80. package/dist/errors/invalid-token.js +3 -0
  81. package/dist/errors/method-not-allowed.d.ts +6 -0
  82. package/dist/errors/method-not-allowed.js +6 -0
  83. package/dist/errors/not-null-violation.d.ts +6 -0
  84. package/dist/errors/not-null-violation.js +14 -0
  85. package/dist/errors/range-not-satisfiable.d.ts +7 -0
  86. package/dist/errors/range-not-satisfiable.js +7 -0
  87. package/dist/errors/record-not-unique.d.ts +6 -0
  88. package/dist/errors/record-not-unique.js +14 -0
  89. package/dist/errors/route-not-found.d.ts +5 -0
  90. package/dist/errors/route-not-found.js +4 -0
  91. package/dist/errors/service-unavailable.d.ts +7 -0
  92. package/dist/errors/service-unavailable.js +4 -0
  93. package/dist/errors/token-expired.d.ts +1 -0
  94. package/dist/errors/token-expired.js +3 -0
  95. package/dist/errors/unexpected-response.d.ts +1 -0
  96. package/dist/errors/unexpected-response.js +3 -0
  97. package/dist/errors/unprocessable-content.d.ts +5 -0
  98. package/dist/errors/unprocessable-content.js +4 -0
  99. package/dist/errors/unsupported-media-type.d.ts +6 -0
  100. package/dist/errors/unsupported-media-type.js +4 -0
  101. package/dist/errors/user-suspended.d.ts +1 -0
  102. package/dist/errors/user-suspended.js +3 -0
  103. package/dist/errors/value-out-of-range.d.ts +6 -0
  104. package/dist/errors/value-out-of-range.js +14 -0
  105. package/dist/errors/value-too-long.d.ts +6 -0
  106. package/dist/errors/value-too-long.js +14 -0
  107. package/dist/extensions.js +0 -4
  108. package/dist/flows.js +6 -8
  109. package/dist/index.d.ts +0 -2
  110. package/dist/index.js +0 -2
  111. package/dist/messenger.d.ts +3 -3
  112. package/dist/messenger.js +18 -9
  113. package/dist/middleware/authenticate.js +2 -38
  114. package/dist/middleware/check-ip.js +2 -2
  115. package/dist/middleware/collection-exists.js +2 -2
  116. package/dist/middleware/error-handler.js +7 -7
  117. package/dist/middleware/graphql.js +11 -9
  118. package/dist/middleware/rate-limiter-global.d.ts +2 -2
  119. package/dist/middleware/rate-limiter-global.js +2 -3
  120. package/dist/middleware/rate-limiter-ip.d.ts +2 -2
  121. package/dist/middleware/rate-limiter-ip.js +2 -3
  122. package/dist/middleware/validate-batch.js +3 -4
  123. package/dist/rate-limiter.js +2 -9
  124. package/dist/server.js +10 -0
  125. package/dist/services/activity.js +3 -2
  126. package/dist/services/assets.js +9 -10
  127. package/dist/services/authentication.js +12 -11
  128. package/dist/services/authorization.d.ts +1 -1
  129. package/dist/services/authorization.js +16 -16
  130. package/dist/services/collections.js +17 -16
  131. package/dist/services/fields.js +16 -14
  132. package/dist/services/files.js +7 -6
  133. package/dist/services/graphql/errors/execution.d.ts +6 -0
  134. package/dist/services/graphql/errors/execution.js +2 -0
  135. package/dist/services/graphql/errors/index.d.ts +2 -0
  136. package/dist/services/graphql/errors/index.js +2 -0
  137. package/dist/services/graphql/errors/validation.d.ts +6 -0
  138. package/dist/services/graphql/errors/validation.js +2 -0
  139. package/dist/services/graphql/index.d.ts +2 -8
  140. package/dist/services/graphql/index.js +125 -66
  141. package/dist/services/graphql/subscription.d.ts +16 -0
  142. package/dist/services/graphql/subscription.js +77 -0
  143. package/dist/services/graphql/utils/process-error.js +3 -3
  144. package/dist/services/import-export.js +7 -7
  145. package/dist/services/index.d.ts +1 -0
  146. package/dist/services/index.js +1 -0
  147. package/dist/services/items.js +14 -13
  148. package/dist/services/mail/index.js +3 -3
  149. package/dist/services/meta.js +3 -3
  150. package/dist/services/payload.js +11 -7
  151. package/dist/services/relations.js +32 -22
  152. package/dist/services/revisions.js +3 -3
  153. package/dist/services/roles.js +10 -9
  154. package/dist/services/schema.js +5 -5
  155. package/dist/services/server.js +24 -0
  156. package/dist/services/shares.js +4 -4
  157. package/dist/services/tfa.js +6 -6
  158. package/dist/services/translations.d.ts +2 -2
  159. package/dist/services/translations.js +4 -4
  160. package/dist/services/users.js +26 -29
  161. package/dist/services/utils.js +4 -4
  162. package/dist/services/websocket.d.ts +14 -0
  163. package/dist/services/websocket.js +26 -0
  164. package/dist/synchronization.js +3 -3
  165. package/dist/types/items.d.ts +2 -2
  166. package/dist/utils/apply-diff.js +13 -4
  167. package/dist/utils/apply-query.js +22 -13
  168. package/dist/utils/get-accountability-for-role.js +1 -2
  169. package/dist/utils/get-accountability-for-token.d.ts +2 -0
  170. package/dist/utils/get-accountability-for-token.js +50 -0
  171. package/dist/utils/get-column-path.js +5 -3
  172. package/dist/utils/get-column.js +3 -3
  173. package/dist/utils/get-service.d.ts +7 -0
  174. package/dist/utils/get-service.js +49 -0
  175. package/dist/utils/jwt.js +5 -5
  176. package/dist/utils/redact.d.ts +4 -0
  177. package/dist/utils/redact.js +15 -1
  178. package/dist/utils/to-boolean.d.ts +4 -0
  179. package/dist/utils/to-boolean.js +6 -0
  180. package/dist/utils/validate-diff.js +23 -9
  181. package/dist/utils/validate-keys.js +3 -3
  182. package/dist/utils/validate-query.d.ts +2 -0
  183. package/dist/utils/validate-query.js +27 -21
  184. package/dist/utils/validate-snapshot.js +11 -5
  185. package/dist/websocket/authenticate.d.ts +6 -0
  186. package/dist/websocket/authenticate.js +59 -0
  187. package/dist/websocket/controllers/base.d.ts +42 -0
  188. package/dist/websocket/controllers/base.js +279 -0
  189. package/dist/websocket/controllers/graphql.d.ts +12 -0
  190. package/dist/websocket/controllers/graphql.js +102 -0
  191. package/dist/websocket/controllers/hooks.d.ts +1 -0
  192. package/dist/websocket/controllers/hooks.js +122 -0
  193. package/dist/websocket/controllers/index.d.ts +10 -0
  194. package/dist/websocket/controllers/index.js +31 -0
  195. package/dist/websocket/controllers/rest.d.ts +9 -0
  196. package/dist/websocket/controllers/rest.js +47 -0
  197. package/dist/websocket/errors.d.ts +16 -0
  198. package/dist/websocket/errors.js +55 -0
  199. package/dist/websocket/handlers/heartbeat.d.ts +11 -0
  200. package/dist/websocket/handlers/heartbeat.js +72 -0
  201. package/dist/websocket/handlers/index.d.ts +4 -0
  202. package/dist/websocket/handlers/index.js +11 -0
  203. package/dist/websocket/handlers/items.d.ts +6 -0
  204. package/dist/websocket/handlers/items.js +103 -0
  205. package/dist/websocket/handlers/subscribe.d.ts +43 -0
  206. package/dist/websocket/handlers/subscribe.js +278 -0
  207. package/dist/websocket/messages.d.ts +311 -0
  208. package/dist/websocket/messages.js +96 -0
  209. package/dist/websocket/types.d.ts +34 -0
  210. package/dist/websocket/types.js +1 -0
  211. package/dist/websocket/utils/get-expires-at-for-token.d.ts +1 -0
  212. package/dist/websocket/utils/get-expires-at-for-token.js +8 -0
  213. package/dist/websocket/utils/message.d.ts +4 -0
  214. package/dist/websocket/utils/message.js +27 -0
  215. package/dist/websocket/utils/wait-for-message.d.ts +4 -0
  216. package/dist/websocket/utils/wait-for-message.js +45 -0
  217. package/package.json +21 -16
  218. package/dist/exceptions/content-too-large.d.ts +0 -4
  219. package/dist/exceptions/content-too-large.js +0 -6
  220. package/dist/exceptions/database/contains-null-values.d.ts +0 -9
  221. package/dist/exceptions/database/contains-null-values.js +0 -6
  222. package/dist/exceptions/database/invalid-foreign-key.d.ts +0 -10
  223. package/dist/exceptions/database/invalid-foreign-key.js +0 -11
  224. package/dist/exceptions/database/not-null-violation.d.ts +0 -9
  225. package/dist/exceptions/database/not-null-violation.js +0 -6
  226. package/dist/exceptions/database/record-not-unique.d.ts +0 -10
  227. package/dist/exceptions/database/record-not-unique.js +0 -11
  228. package/dist/exceptions/database/value-out-of-range.d.ts +0 -10
  229. package/dist/exceptions/database/value-out-of-range.js +0 -11
  230. package/dist/exceptions/database/value-too-long.d.ts +0 -9
  231. package/dist/exceptions/database/value-too-long.js +0 -11
  232. package/dist/exceptions/forbidden.d.ts +0 -6
  233. package/dist/exceptions/forbidden.js +0 -13
  234. package/dist/exceptions/graphql-validation.d.ts +0 -4
  235. package/dist/exceptions/graphql-validation.js +0 -6
  236. package/dist/exceptions/hit-rate-limit.d.ts +0 -9
  237. package/dist/exceptions/hit-rate-limit.js +0 -6
  238. package/dist/exceptions/illegal-asset-transformation.d.ts +0 -4
  239. package/dist/exceptions/illegal-asset-transformation.js +0 -6
  240. package/dist/exceptions/index.d.ts +0 -21
  241. package/dist/exceptions/index.js +0 -21
  242. package/dist/exceptions/invalid-config.d.ts +0 -4
  243. package/dist/exceptions/invalid-config.js +0 -6
  244. package/dist/exceptions/invalid-credentials.d.ts +0 -4
  245. package/dist/exceptions/invalid-credentials.js +0 -6
  246. package/dist/exceptions/invalid-ip.d.ts +0 -4
  247. package/dist/exceptions/invalid-ip.js +0 -6
  248. package/dist/exceptions/invalid-otp.d.ts +0 -4
  249. package/dist/exceptions/invalid-otp.js +0 -6
  250. package/dist/exceptions/invalid-payload.d.ts +0 -4
  251. package/dist/exceptions/invalid-payload.js +0 -6
  252. package/dist/exceptions/invalid-provider.d.ts +0 -4
  253. package/dist/exceptions/invalid-provider.js +0 -6
  254. package/dist/exceptions/invalid-query.d.ts +0 -4
  255. package/dist/exceptions/invalid-query.js +0 -6
  256. package/dist/exceptions/invalid-token.d.ts +0 -4
  257. package/dist/exceptions/invalid-token.js +0 -6
  258. package/dist/exceptions/method-not-allowed.d.ts +0 -8
  259. package/dist/exceptions/method-not-allowed.js +0 -6
  260. package/dist/exceptions/range-not-satisfiable.d.ts +0 -5
  261. package/dist/exceptions/range-not-satisfiable.js +0 -9
  262. package/dist/exceptions/route-not-found.d.ts +0 -4
  263. package/dist/exceptions/route-not-found.js +0 -6
  264. package/dist/exceptions/service-unavailable.d.ts +0 -9
  265. package/dist/exceptions/service-unavailable.js +0 -6
  266. package/dist/exceptions/token-expired.d.ts +0 -4
  267. package/dist/exceptions/token-expired.js +0 -6
  268. package/dist/exceptions/unexpected-response.d.ts +0 -4
  269. package/dist/exceptions/unexpected-response.js +0 -6
  270. package/dist/exceptions/unprocessable-entity.d.ts +0 -4
  271. package/dist/exceptions/unprocessable-entity.js +0 -6
  272. package/dist/exceptions/unsupported-media-type.d.ts +0 -4
  273. package/dist/exceptions/unsupported-media-type.js +0 -6
  274. package/dist/exceptions/user-suspended.d.ts +0 -4
  275. package/dist/exceptions/user-suspended.js +0 -6
  276. /package/dist/{exceptions/database → database/errors}/dialects/mssql.d.ts +0 -0
  277. /package/dist/{exceptions/database → database/errors}/dialects/mysql.d.ts +0 -0
  278. /package/dist/{exceptions/database → database/errors}/dialects/oracle.d.ts +0 -0
  279. /package/dist/{exceptions/database → database/errors}/dialects/postgres.d.ts +0 -0
  280. /package/dist/{exceptions/database → database/errors}/dialects/sqlite.d.ts +0 -0
  281. /package/dist/{exceptions/database → database/errors}/dialects/types.d.ts +0 -0
  282. /package/dist/{exceptions/database → database/errors}/dialects/types.js +0 -0
  283. /package/dist/{exceptions/database → database/errors}/translate.d.ts +0 -0
package/dist/app.js CHANGED
@@ -39,8 +39,7 @@ import webhooksRouter from './controllers/webhooks.js';
39
39
  import { isInstalled, validateDatabaseConnection, validateDatabaseExtensions, validateMigrations, } from './database/index.js';
40
40
  import emitter from './emitter.js';
41
41
  import env from './env.js';
42
- import { InvalidPayloadException } from './exceptions/invalid-payload.js';
43
- import { ServiceUnavailableException } from './exceptions/service-unavailable.js';
42
+ import { InvalidPayloadError, ServiceUnavailableError } from './errors/index.js';
44
43
  import { getExtensionManager } from './extensions.js';
45
44
  import { getFlowManager } from './flows.js';
46
45
  import logger, { expressLogger } from './logger.js';
@@ -98,7 +97,7 @@ export default async function createApp() {
98
97
  maxEventLoopDelay: env['PRESSURE_LIMITER_MAX_EVENT_LOOP_DELAY'],
99
98
  maxMemoryRss: env['PRESSURE_LIMITER_MAX_MEMORY_RSS'],
100
99
  maxMemoryHeapUsed: env['PRESSURE_LIMITER_MAX_MEMORY_HEAP_USED'],
101
- error: new ServiceUnavailableException('Under pressure', { service: 'api' }),
100
+ error: new ServiceUnavailableError({ service: 'api', reason: 'Under pressure' }),
102
101
  retryAfter: env['PRESSURE_LIMITER_RETRY_AFTER'],
103
102
  }));
104
103
  }
@@ -137,7 +136,7 @@ export default async function createApp() {
137
136
  limit: env['MAX_PAYLOAD_SIZE'],
138
137
  })(req, res, (err) => {
139
138
  if (err) {
140
- return next(new InvalidPayloadException(err.message));
139
+ return next(new InvalidPayloadError({ reason: err.message }));
141
140
  }
142
141
  return next();
143
142
  });
@@ -9,7 +9,7 @@ export declare abstract class AuthDriver {
9
9
  * Get user id for a given provider payload
10
10
  *
11
11
  * @param payload Any data that the user might've provided
12
- * @throws InvalidCredentialsException
12
+ * @throws InvalidCredentialsError
13
13
  * @return User id of the identifier
14
14
  */
15
15
  abstract getUserID(payload: Record<string, any>): Promise<string>;
@@ -18,7 +18,7 @@ export declare abstract class AuthDriver {
18
18
  *
19
19
  * @param user User information
20
20
  * @param password User password
21
- * @throws InvalidCredentialsException
21
+ * @throws InvalidCredentialsError
22
22
  */
23
23
  abstract verify(user: User, password?: string): Promise<void>;
24
24
  /**
@@ -26,7 +26,7 @@ export declare abstract class AuthDriver {
26
26
  *
27
27
  * @param _user User information
28
28
  * @param _payload Any data that the user might've provided
29
- * @throws InvalidCredentialsException
29
+ * @throws InvalidCredentialsError
30
30
  * @returns Data to be stored with the session
31
31
  */
32
32
  login(_user: User, _payload: Record<string, any>): Promise<void>;
@@ -34,7 +34,7 @@ export declare abstract class AuthDriver {
34
34
  * Handle user session refresh
35
35
  *
36
36
  * @param _user User information
37
- * @throws InvalidCredentialsException
37
+ * @throws InvalidCredentialsError
38
38
  */
39
39
  refresh(_user: User): Promise<void>;
40
40
  /**
package/dist/auth/auth.js CHANGED
@@ -10,7 +10,7 @@ export class AuthDriver {
10
10
  *
11
11
  * @param _user User information
12
12
  * @param _payload Any data that the user might've provided
13
- * @throws InvalidCredentialsException
13
+ * @throws InvalidCredentialsError
14
14
  * @returns Data to be stored with the session
15
15
  */
16
16
  async login(_user, _payload) {
@@ -20,7 +20,7 @@ export class AuthDriver {
20
20
  * Handle user session refresh
21
21
  *
22
22
  * @param _user User information
23
- * @throws InvalidCredentialsException
23
+ * @throws InvalidCredentialsError
24
24
  */
25
25
  async refresh(_user) {
26
26
  return;
@@ -1,11 +1,11 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import { Router } from 'express';
2
3
  import Joi from 'joi';
3
4
  import ldap from 'ldapjs';
4
5
  import getDatabase from '../../database/index.js';
5
6
  import emitter from '../../emitter.js';
6
7
  import env from '../../env.js';
7
- import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js';
8
- import { InvalidConfigException, InvalidCredentialsException, InvalidPayloadException, InvalidProviderException, ServiceUnavailableException, UnexpectedResponseException, } from '../../exceptions/index.js';
8
+ import { ErrorCode, InvalidCredentialsError, InvalidPayloadError, InvalidProviderError, InvalidProviderConfigError, ServiceUnavailableError, UnexpectedResponseError, } from '../../errors/index.js';
9
9
  import logger from '../../logger.js';
10
10
  import { respond } from '../../middleware/respond.js';
11
11
  import { AuthenticationService } from '../../services/authentication.js';
@@ -30,7 +30,8 @@ export class LDAPAuthDriver extends AuthDriver {
30
30
  !userDn ||
31
31
  !provider ||
32
32
  (!clientUrl && !config['client']?.socketPath)) {
33
- throw new InvalidConfigException('Invalid provider config', { provider });
33
+ logger.error('Invalid provider config');
34
+ throw new InvalidProviderConfigError({ provider });
34
35
  }
35
36
  const clientConfig = typeof config['client'] === 'object' ? config['client'] : {};
36
37
  this.bindClient = ldap.createClient({ url: clientUrl, reconnect: true, ...clientConfig });
@@ -57,8 +58,9 @@ export class LDAPAuthDriver extends AuthDriver {
57
58
  this.bindClient.bind(bindDn, bindPassword, (err) => {
58
59
  if (err) {
59
60
  const error = handleError(err);
60
- if (error instanceof InvalidCredentialsException) {
61
- reject(new InvalidConfigException('Invalid bind user', { provider }));
61
+ if (isDirectusError(error, ErrorCode.InvalidCredentials)) {
62
+ logger.warn('Invalid bind user');
63
+ reject(new InvalidProviderConfigError({ provider }));
62
64
  }
63
65
  else {
64
66
  reject(error);
@@ -72,7 +74,8 @@ export class LDAPAuthDriver extends AuthDriver {
72
74
  res.on('end', (result) => {
73
75
  // Handle edge case where authenticated bind user cannot read their own DN
74
76
  if (result?.status === 0) {
75
- reject(new UnexpectedResponseException('Failed to find bind user record'));
77
+ logger.warn('[LDAP] Failed to find bind user record');
78
+ reject(new UnexpectedResponseError());
76
79
  }
77
80
  });
78
81
  });
@@ -162,7 +165,7 @@ export class LDAPAuthDriver extends AuthDriver {
162
165
  }
163
166
  async getUserID(payload) {
164
167
  if (!payload['identifier']) {
165
- throw new InvalidCredentialsException();
168
+ throw new InvalidCredentialsError();
166
169
  }
167
170
  await this.validateBindClient();
168
171
  const { userDn, userScope, userAttribute, groupDn, groupScope, groupAttribute, defaultRoleId } = this.config;
@@ -171,7 +174,7 @@ export class LDAPAuthDriver extends AuthDriver {
171
174
  value: payload['identifier'],
172
175
  }), userScope ?? 'one');
173
176
  if (!userInfo?.dn) {
174
- throw new InvalidCredentialsException();
177
+ throw new InvalidCredentialsError();
175
178
  }
176
179
  let userRole;
177
180
  if (groupDn) {
@@ -204,7 +207,7 @@ export class LDAPAuthDriver extends AuthDriver {
204
207
  return userId;
205
208
  }
206
209
  if (!userInfo) {
207
- throw new InvalidCredentialsException();
210
+ throw new InvalidCredentialsError();
208
211
  }
209
212
  const userPayload = {
210
213
  provider: this.config['provider'],
@@ -221,9 +224,9 @@ export class LDAPAuthDriver extends AuthDriver {
221
224
  await this.usersService.createOne(updatedUserPayload);
222
225
  }
223
226
  catch (e) {
224
- if (e instanceof RecordNotUniqueException) {
227
+ if (isDirectusError(e, ErrorCode.RecordNotUnique)) {
225
228
  logger.warn(e, '[LDAP] Failed to register user. User not unique');
226
- throw new InvalidProviderException();
229
+ throw new InvalidProviderError();
227
230
  }
228
231
  throw e;
229
232
  }
@@ -231,7 +234,7 @@ export class LDAPAuthDriver extends AuthDriver {
231
234
  }
232
235
  async verify(user, password) {
233
236
  if (!user.external_identifier || !password) {
234
- throw new InvalidCredentialsException();
237
+ throw new InvalidCredentialsError();
235
238
  }
236
239
  return new Promise((resolve, reject) => {
237
240
  const clientConfig = typeof this.config['client'] === 'object' ? this.config['client'] : {};
@@ -261,7 +264,7 @@ export class LDAPAuthDriver extends AuthDriver {
261
264
  await this.validateBindClient();
262
265
  const userInfo = await this.fetchUserInfo(user.external_identifier);
263
266
  if (userInfo?.userAccountControl && userInfo.userAccountControl & INVALID_ACCOUNT_FLAGS) {
264
- throw new InvalidCredentialsException();
267
+ throw new InvalidCredentialsError();
265
268
  }
266
269
  }
267
270
  }
@@ -269,11 +272,11 @@ const handleError = (e) => {
269
272
  if (e instanceof ldap.InappropriateAuthenticationError ||
270
273
  e instanceof ldap.InvalidCredentialsError ||
271
274
  e instanceof ldap.InsufficientAccessRightsError) {
272
- return new InvalidCredentialsException();
275
+ return new InvalidCredentialsError();
273
276
  }
274
- return new ServiceUnavailableException('Service returned unexpected error', {
277
+ return new ServiceUnavailableError({
275
278
  service: 'ldap',
276
- message: e.message,
279
+ reason: `Service returned unexpected error: ${e.message}`,
277
280
  });
278
281
  };
279
282
  const getEntryValue = (value) => {
@@ -304,7 +307,7 @@ export function createLDAPAuthRouter(provider) {
304
307
  });
305
308
  const { error } = loginSchema.validate(req.body);
306
309
  if (error) {
307
- throw new InvalidPayloadException(error.message);
310
+ throw new InvalidPayloadError({ reason: error.message });
308
311
  }
309
312
  const mode = req.body.mode || 'json';
310
313
  const { accessToken, refreshToken, expires } = await authenticationService.login(provider, req.body, req.body?.otp);
@@ -4,7 +4,7 @@ import Joi from 'joi';
4
4
  import { performance } from 'perf_hooks';
5
5
  import { COOKIE_OPTIONS } from '../../constants.js';
6
6
  import env from '../../env.js';
7
- import { InvalidCredentialsException, InvalidPayloadException } from '../../exceptions/index.js';
7
+ import { InvalidCredentialsError, InvalidPayloadError } from '../../errors/index.js';
8
8
  import { respond } from '../../middleware/respond.js';
9
9
  import { AuthenticationService } from '../../services/authentication.js';
10
10
  import asyncHandler from '../../utils/async-handler.js';
@@ -14,7 +14,7 @@ import { AuthDriver } from '../auth.js';
14
14
  export class LocalAuthDriver extends AuthDriver {
15
15
  async getUserID(payload) {
16
16
  if (!payload['email']) {
17
- throw new InvalidCredentialsException();
17
+ throw new InvalidCredentialsError();
18
18
  }
19
19
  const user = await this.knex
20
20
  .select('id')
@@ -22,13 +22,13 @@ export class LocalAuthDriver extends AuthDriver {
22
22
  .whereRaw('LOWER(??) = ?', ['email', payload['email'].toLowerCase()])
23
23
  .first();
24
24
  if (!user) {
25
- throw new InvalidCredentialsException();
25
+ throw new InvalidCredentialsError();
26
26
  }
27
27
  return user.id;
28
28
  }
29
29
  async verify(user, password) {
30
30
  if (!user.password || !(await argon2.verify(user.password, password))) {
31
- throw new InvalidCredentialsException();
31
+ throw new InvalidCredentialsError();
32
32
  }
33
33
  }
34
34
  async login(user, payload) {
@@ -63,7 +63,7 @@ export function createLocalAuthRouter(provider) {
63
63
  const { error } = userLoginSchema.validate(req.body);
64
64
  if (error) {
65
65
  await stall(STALL_TIME, timeStart);
66
- throw new InvalidPayloadException(error.message);
66
+ throw new InvalidPayloadError({ reason: error.message });
67
67
  }
68
68
  const mode = req.body.mode || 'json';
69
69
  const { accessToken, refreshToken, expires } = await authenticationService.login(provider, req.body, req.body?.otp);
@@ -1,4 +1,4 @@
1
- import { BaseException } from '@directus/exceptions';
1
+ import { isDirectusError } from '@directus/errors';
2
2
  import { parseJSON } from '@directus/utils';
3
3
  import express, { Router } from 'express';
4
4
  import flatten from 'flat';
@@ -8,8 +8,7 @@ import { getAuthProvider } from '../../auth.js';
8
8
  import getDatabase from '../../database/index.js';
9
9
  import emitter from '../../emitter.js';
10
10
  import env from '../../env.js';
11
- import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js';
12
- import { InvalidConfigException, InvalidCredentialsException, InvalidProviderException, InvalidTokenException, ServiceUnavailableException, } from '../../exceptions/index.js';
11
+ import { ErrorCode, InvalidCredentialsError, InvalidProviderError, InvalidProviderConfigError, InvalidTokenError, ServiceUnavailableError, } from '../../errors/index.js';
13
12
  import logger from '../../logger.js';
14
13
  import { respond } from '../../middleware/respond.js';
15
14
  import { AuthenticationService } from '../../services/authentication.js';
@@ -29,7 +28,8 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
29
28
  super(options, config);
30
29
  const { authorizeUrl, accessUrl, profileUrl, clientId, clientSecret, ...additionalConfig } = config;
31
30
  if (!authorizeUrl || !accessUrl || !profileUrl || !clientId || !clientSecret || !additionalConfig['provider']) {
32
- throw new InvalidConfigException('Invalid provider config', { provider: additionalConfig['provider'] });
31
+ logger.error('Invalid provider config');
32
+ throw new InvalidProviderConfigError({ provider: additionalConfig['provider'] });
33
33
  }
34
34
  const redirectUrl = new Url(env['PUBLIC_URL']).addPath('auth', 'login', additionalConfig['provider'], 'callback');
35
35
  this.redirectUrl = redirectUrl.toString();
@@ -83,7 +83,7 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
83
83
  async getUserID(payload) {
84
84
  if (!payload['code'] || !payload['codeVerifier'] || !payload['state']) {
85
85
  logger.warn('[OAuth2] No code, codeVerifier or state in payload');
86
- throw new InvalidCredentialsException();
86
+ throw new InvalidCredentialsError();
87
87
  }
88
88
  let tokenSet;
89
89
  let userInfo;
@@ -102,7 +102,7 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
102
102
  const identifier = userInfo[identifierKey] ? String(userInfo[identifierKey]) : email;
103
103
  if (!identifier) {
104
104
  logger.warn(`[OAuth2] Failed to find user identifier for provider "${provider}"`);
105
- throw new InvalidCredentialsException();
105
+ throw new InvalidCredentialsError();
106
106
  }
107
107
  const userPayload = {
108
108
  provider,
@@ -129,7 +129,7 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
129
129
  // Is public registration allowed?
130
130
  if (!allowPublicRegistration) {
131
131
  logger.warn(`[OAuth2] User doesn't exist, and public registration not allowed for provider "${provider}"`);
132
- throw new InvalidCredentialsException();
132
+ throw new InvalidCredentialsError();
133
133
  }
134
134
  // Run hook so the end user has the chance to augment the
135
135
  // user that is about to be created
@@ -142,9 +142,9 @@ export class OAuth2AuthDriver extends LocalAuthDriver {
142
142
  await this.usersService.createOne(updatedUserPayload);
143
143
  }
144
144
  catch (e) {
145
- if (e instanceof RecordNotUniqueException) {
145
+ if (isDirectusError(e, ErrorCode.RecordNotUnique)) {
146
146
  logger.warn(e, '[OAuth2] Failed to register user. User not unique');
147
- throw new InvalidProviderException();
147
+ throw new InvalidProviderError();
148
148
  }
149
149
  throw e;
150
150
  }
@@ -184,19 +184,19 @@ const handleError = (e) => {
184
184
  if (e.error === 'invalid_grant') {
185
185
  // Invalid token
186
186
  logger.trace(e, `[OAuth2] Invalid grant`);
187
- return new InvalidTokenException();
187
+ return new InvalidTokenError();
188
188
  }
189
189
  // Server response error
190
190
  logger.trace(e, `[OAuth2] Unknown OP error`);
191
- return new ServiceUnavailableException('Service returned unexpected response', {
191
+ return new ServiceUnavailableError({
192
192
  service: 'oauth2',
193
- message: e.error_description,
193
+ reason: `Service returned unexpected response: ${e.error_description}`,
194
194
  });
195
195
  }
196
196
  else if (e instanceof errors.RPError) {
197
197
  // Internal client error
198
198
  logger.trace(e, `[OAuth2] Unknown RP error`);
199
- return new InvalidCredentialsException();
199
+ return new InvalidCredentialsError();
200
200
  }
201
201
  logger.trace(e, `[OAuth2] Unknown error`);
202
202
  return e;
@@ -229,7 +229,7 @@ export function createOAuth2AuthRouter(providerName) {
229
229
  }
230
230
  catch (e) {
231
231
  logger.warn(e, `[OAuth2] Couldn't verify OAuth2 cookie`);
232
- throw new InvalidCredentialsException();
232
+ throw new InvalidCredentialsError();
233
233
  }
234
234
  const { verifier, redirect, prompt } = tokenData;
235
235
  const accountability = {
@@ -257,12 +257,12 @@ export function createOAuth2AuthRouter(providerName) {
257
257
  }
258
258
  catch (error) {
259
259
  // Prompt user for a new refresh_token if invalidated
260
- if (error instanceof InvalidTokenException && !prompt) {
260
+ if (isDirectusError(error, ErrorCode.InvalidToken) && !prompt) {
261
261
  return res.redirect(`./?${redirect ? `redirect=${redirect}&` : ''}prompt=true`);
262
262
  }
263
263
  if (redirect) {
264
264
  let reason = 'UNKNOWN_EXCEPTION';
265
- if (error instanceof BaseException) {
265
+ if (isDirectusError(error)) {
266
266
  reason = error.code;
267
267
  }
268
268
  else {
@@ -1,4 +1,4 @@
1
- import { BaseException } from '@directus/exceptions';
1
+ import { isDirectusError } from '@directus/errors';
2
2
  import { parseJSON } from '@directus/utils';
3
3
  import express, { Router } from 'express';
4
4
  import flatten from 'flat';
@@ -8,8 +8,7 @@ import { getAuthProvider } from '../../auth.js';
8
8
  import getDatabase from '../../database/index.js';
9
9
  import emitter from '../../emitter.js';
10
10
  import env from '../../env.js';
11
- import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js';
12
- import { InvalidConfigException, InvalidCredentialsException, InvalidProviderException, InvalidTokenException, ServiceUnavailableException, } from '../../exceptions/index.js';
11
+ import { ErrorCode, InvalidCredentialsError, InvalidProviderError, InvalidProviderConfigError, InvalidTokenError, ServiceUnavailableError, } from '../../errors/index.js';
13
12
  import logger from '../../logger.js';
14
13
  import { respond } from '../../middleware/respond.js';
15
14
  import { AuthenticationService } from '../../services/authentication.js';
@@ -29,7 +28,8 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
29
28
  super(options, config);
30
29
  const { issuerUrl, clientId, clientSecret, ...additionalConfig } = config;
31
30
  if (!issuerUrl || !clientId || !clientSecret || !additionalConfig['provider']) {
32
- throw new InvalidConfigException('Invalid provider config', { provider: additionalConfig['provider'] });
31
+ logger.error('Invalid provider config');
32
+ throw new InvalidProviderConfigError({ provider: additionalConfig['provider'] });
33
33
  }
34
34
  const redirectUrl = new Url(env['PUBLIC_URL']).addPath('auth', 'login', additionalConfig['provider'], 'callback');
35
35
  const clientOptionsOverrides = getConfigFromEnv(`AUTH_${config['provider'].toUpperCase()}_CLIENT_`, [`AUTH_${config['provider'].toUpperCase()}_CLIENT_ID`, `AUTH_${config['provider'].toUpperCase()}_CLIENT_SECRET`], 'underscore');
@@ -41,7 +41,8 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
41
41
  .then((issuer) => {
42
42
  const supportedTypes = issuer.metadata['response_types_supported'];
43
43
  if (!supportedTypes?.includes('code')) {
44
- reject(new InvalidConfigException('OpenID provider does not support required code flow', {
44
+ logger.error('OpenID provider does not support required code flow');
45
+ reject(new InvalidProviderConfigError({
45
46
  provider: additionalConfig['provider'],
46
47
  }));
47
48
  }
@@ -94,7 +95,7 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
94
95
  async getUserID(payload) {
95
96
  if (!payload['code'] || !payload['codeVerifier'] || !payload['state']) {
96
97
  logger.warn('[OpenID] No code, codeVerifier or state in payload');
97
- throw new InvalidCredentialsException();
98
+ throw new InvalidCredentialsError();
98
99
  }
99
100
  let tokenSet;
100
101
  let userInfo;
@@ -121,7 +122,7 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
121
122
  const identifier = userInfo[identifierKey ?? 'sub'] ? String(userInfo[identifierKey ?? 'sub']) : email;
122
123
  if (!identifier) {
123
124
  logger.warn(`[OpenID] Failed to find user identifier for provider "${provider}"`);
124
- throw new InvalidCredentialsException();
125
+ throw new InvalidCredentialsError();
125
126
  }
126
127
  const userPayload = {
127
128
  provider,
@@ -149,7 +150,7 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
149
150
  // Is public registration allowed?
150
151
  if (!allowPublicRegistration || !isEmailVerified) {
151
152
  logger.warn(`[OpenID] User doesn't exist, and public registration not allowed for provider "${provider}"`);
152
- throw new InvalidCredentialsException();
153
+ throw new InvalidCredentialsError();
153
154
  }
154
155
  // Run hook so the end user has the chance to augment the
155
156
  // user that is about to be created
@@ -162,9 +163,9 @@ export class OpenIDAuthDriver extends LocalAuthDriver {
162
163
  await this.usersService.createOne(updatedUserPayload);
163
164
  }
164
165
  catch (e) {
165
- if (e instanceof RecordNotUniqueException) {
166
+ if (isDirectusError(e, ErrorCode.RecordNotUnique)) {
166
167
  logger.warn(e, '[OpenID] Failed to register user. User not unique');
167
- throw new InvalidProviderException();
168
+ throw new InvalidProviderError();
168
169
  }
169
170
  throw e;
170
171
  }
@@ -205,19 +206,19 @@ const handleError = (e) => {
205
206
  if (e.error === 'invalid_grant') {
206
207
  // Invalid token
207
208
  logger.trace(e, `[OpenID] Invalid grant`);
208
- return new InvalidTokenException();
209
+ return new InvalidTokenError();
209
210
  }
210
211
  // Server response error
211
212
  logger.trace(e, `[OpenID] Unknown OP error`);
212
- return new ServiceUnavailableException('Service returned unexpected response', {
213
+ return new ServiceUnavailableError({
213
214
  service: 'openid',
214
- message: e.error_description,
215
+ reason: `Service returned unexpected response: ${e.error_description}`,
215
216
  });
216
217
  }
217
218
  else if (e instanceof errors.RPError) {
218
219
  // Internal client error
219
220
  logger.trace(e, `[OpenID] Unknown RP error`);
220
- return new InvalidCredentialsException();
221
+ return new InvalidCredentialsError();
221
222
  }
222
223
  logger.trace(e, `[OpenID] Unknown error`);
223
224
  return e;
@@ -250,7 +251,7 @@ export function createOpenIDAuthRouter(providerName) {
250
251
  }
251
252
  catch (e) {
252
253
  logger.warn(e, `[OpenID] Couldn't verify OpenID cookie`);
253
- throw new InvalidCredentialsException();
254
+ throw new InvalidCredentialsError();
254
255
  }
255
256
  const { verifier, redirect, prompt } = tokenData;
256
257
  const accountability = {
@@ -279,13 +280,13 @@ export function createOpenIDAuthRouter(providerName) {
279
280
  }
280
281
  catch (error) {
281
282
  // Prompt user for a new refresh_token if invalidated
282
- if (error instanceof InvalidTokenException && !prompt) {
283
+ if (isDirectusError(error, ErrorCode.InvalidToken) && !prompt) {
283
284
  return res.redirect(`./?${redirect ? `redirect=${redirect}&` : ''}prompt=true`);
284
285
  }
285
286
  logger.warn(error);
286
287
  if (redirect) {
287
288
  let reason = 'UNKNOWN_EXCEPTION';
288
- if (error instanceof BaseException) {
289
+ if (isDirectusError(error)) {
289
290
  reason = error.code;
290
291
  }
291
292
  else {
@@ -1,5 +1,5 @@
1
1
  import * as validator from '@authenio/samlify-node-xmllint';
2
- import { BaseException } from '@directus/exceptions';
2
+ import { isDirectusError } from '@directus/errors';
3
3
  import express, { Router } from 'express';
4
4
  import * as samlify from 'samlify';
5
5
  import { getAuthProvider } from '../../auth.js';
@@ -7,8 +7,7 @@ import { COOKIE_OPTIONS } from '../../constants.js';
7
7
  import getDatabase from '../../database/index.js';
8
8
  import emitter from '../../emitter.js';
9
9
  import env from '../../env.js';
10
- import { RecordNotUniqueException } from '../../exceptions/database/record-not-unique.js';
11
- import { InvalidCredentialsException, InvalidProviderException } from '../../exceptions/index.js';
10
+ import { ErrorCode, InvalidCredentialsError, InvalidProviderError } from '../../errors/index.js';
12
11
  import logger from '../../logger.js';
13
12
  import { respond } from '../../middleware/respond.js';
14
13
  import { AuthenticationService } from '../../services/authentication.js';
@@ -47,7 +46,7 @@ export class SAMLAuthDriver extends LocalAuthDriver {
47
46
  return userID;
48
47
  if (!allowPublicRegistration) {
49
48
  logger.trace(`[SAML] User doesn't exist, and public registration not allowed for provider "${provider}"`);
50
- throw new InvalidCredentialsException();
49
+ throw new InvalidCredentialsError();
51
50
  }
52
51
  const firstName = payload[givenNameKey ?? 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'];
53
52
  const lastName = payload[familyNameKey ?? 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname'];
@@ -66,9 +65,9 @@ export class SAMLAuthDriver extends LocalAuthDriver {
66
65
  return await this.usersService.createOne(updatedUserPayload);
67
66
  }
68
67
  catch (error) {
69
- if (error instanceof RecordNotUniqueException) {
68
+ if (isDirectusError(error, ErrorCode.RecordNotUnique)) {
70
69
  logger.warn(error, '[SAML] Failed to register user. User not unique');
71
- throw new InvalidProviderException();
70
+ throw new InvalidProviderError();
72
71
  }
73
72
  throw error;
74
73
  }
@@ -129,7 +128,7 @@ export function createSAMLAuthRouter(providerName) {
129
128
  catch (error) {
130
129
  if (relayState) {
131
130
  let reason = 'UNKNOWN_EXCEPTION';
132
- if (error instanceof BaseException) {
131
+ if (isDirectusError(error)) {
133
132
  reason = error.code;
134
133
  }
135
134
  else {
package/dist/auth.js CHANGED
@@ -3,7 +3,7 @@ import { LDAPAuthDriver, LocalAuthDriver, OAuth2AuthDriver, OpenIDAuthDriver, SA
3
3
  import { DEFAULT_AUTH_PROVIDER } from './constants.js';
4
4
  import getDatabase from './database/index.js';
5
5
  import env from './env.js';
6
- import { InvalidConfigException } from './exceptions/invalid-config.js';
6
+ import { InvalidProviderConfigError } from './errors/index.js';
7
7
  import logger from './logger.js';
8
8
  import { getConfigFromEnv } from './utils/get-config-from-env.js';
9
9
  import { getSchema } from './utils/get-schema.js';
@@ -11,7 +11,8 @@ const providerNames = toArray(env['AUTH_PROVIDERS']);
11
11
  const providers = new Map();
12
12
  export function getAuthProvider(provider) {
13
13
  if (!providers.has(provider)) {
14
- throw new InvalidConfigException('Auth provider not configured', { provider });
14
+ logger.error('Auth provider not configured');
15
+ throw new InvalidProviderConfigError({ provider });
15
16
  }
16
17
  return providers.get(provider);
17
18
  }
package/dist/cache.js CHANGED
@@ -57,13 +57,14 @@ export async function flushCaches(forced) {
57
57
  await cache?.clear();
58
58
  }
59
59
  export async function clearSystemCache(opts) {
60
- const { systemCache, localSchemaCache, lockCache } = getCache();
60
+ const { systemCache, localSchemaCache, lockCache, sharedSchemaCache } = getCache();
61
61
  // Flush system cache when forced or when system cache lock not set
62
62
  if (opts?.forced || !(await lockCache.get('system-cache-lock'))) {
63
63
  await lockCache.set('system-cache-lock', true, 10000);
64
64
  await systemCache.clear();
65
65
  await lockCache.delete('system-cache-lock');
66
66
  }
67
+ await sharedSchemaCache.clear();
67
68
  await localSchemaCache.clear();
68
69
  messenger.publish('schemaChanged', { autoPurgeCache: opts?.autoPurgeCache });
69
70
  }
@@ -109,8 +110,6 @@ function getKeyvInstance(store, ttl, namespaceSuffix) {
109
110
  switch (store) {
110
111
  case 'redis':
111
112
  return new Keyv(getConfig('redis', ttl, namespaceSuffix));
112
- case 'memcache':
113
- return new Keyv(getConfig('memcache', ttl, namespaceSuffix));
114
113
  case 'memory':
115
114
  default:
116
115
  return new Keyv(getConfig('memory', ttl, namespaceSuffix));
@@ -123,16 +122,7 @@ function getConfig(store = 'memory', ttl, namespaceSuffix = '') {
123
122
  };
124
123
  if (store === 'redis') {
125
124
  const KeyvRedis = require('@keyv/redis');
126
- config.store = new KeyvRedis(env['CACHE_REDIS'] || getConfigFromEnv('CACHE_REDIS_'));
127
- }
128
- if (store === 'memcache') {
129
- const KeyvMemcache = require('keyv-memcache');
130
- // keyv-memcache uses memjs which only accepts a comma separated string instead of an array,
131
- // so we need to join array into a string when applicable. See #7986
132
- const cacheMemcache = Array.isArray(env['CACHE_MEMCACHE'])
133
- ? env['CACHE_MEMCACHE'].join(',')
134
- : env['CACHE_MEMCACHE'];
135
- config.store = new KeyvMemcache(cacheMemcache);
125
+ config.store = new KeyvRedis(env['REDIS'] || getConfigFromEnv('REDIS'));
136
126
  }
137
127
  return config;
138
128
  }
@@ -50,6 +50,9 @@ PUBLIC_URL="/"
50
50
  # The maximum number of items for batch mutations when creating, updating and deleting. ["Infinity"]
51
51
  # MAX_BATCH_MUTATION="Infinity"
52
52
 
53
+ # Shared Redis server for things like caching, rate limiting, container synchronization, etc
54
+ # REDIS="redis://@127.0.0.1:6379"
55
+
53
56
  ####################################################################################################
54
57
  ### Database
55
58
 
@@ -127,10 +130,8 @@ PUBLIC_URL="/"
127
130
  RATE_LIMITER_ENABLED=false
128
131
 
129
132
  # Where to store the rate limiter counts [memory]
130
- # memory, redis, memcache
133
+ # memory, redis
131
134
  RATE_LIMITER_STORE=memory
132
- # RATE_LIMITER_REDIS="redis://@127.0.0.1:5105"
133
- # RATE_LIMITER_MEMCACHE="localhost:5109"
134
135
 
135
136
  # The amount of allowed hits per duration [50]
136
137
  RATE_LIMITER_POINTS=25
@@ -156,15 +157,12 @@ CACHE_ENABLED=false
156
157
  # List of collections that prevent cache purging when `CACHE_AUTO_PURGE` is enabled. ["directus_activity,directus_presets"]
157
158
  # CACHE_AUTO_PURGE_IGNORE_LIST="directus_activity,directus_presets"
158
159
 
159
- # memory | redis | memcache
160
+ # memory | redis
160
161
  CACHE_STORE=memory
161
162
 
162
163
  # How long assets will be cached for in the browser. Sets the max-age value of the Cache-Control header ["30d"]
163
164
  ASSETS_CACHE_TTL="30d"
164
165
 
165
- # CACHE_REDIS="redis://@127.0.0.1:5105"
166
- # CACHE_MEMCACHE="localhost:5109"
167
-
168
166
  ####################################################################################################
169
167
  ### File Storage
170
168