@directus/api 11.1.0 → 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 (246) 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/env.js +6 -13
  47. package/dist/errors/codes.d.ts +29 -0
  48. package/dist/errors/codes.js +30 -0
  49. package/dist/errors/contains-null-values.d.ts +7 -0
  50. package/dist/errors/contains-null-values.js +4 -0
  51. package/dist/errors/content-too-large.d.ts +1 -0
  52. package/dist/errors/content-too-large.js +3 -0
  53. package/dist/errors/forbidden.d.ts +1 -0
  54. package/dist/errors/forbidden.js +3 -0
  55. package/dist/errors/hit-rate-limit.d.ts +6 -0
  56. package/dist/errors/hit-rate-limit.js +8 -0
  57. package/dist/errors/illegal-asset-transformation.d.ts +4 -0
  58. package/dist/errors/illegal-asset-transformation.js +3 -0
  59. package/dist/errors/index.d.ts +28 -0
  60. package/dist/errors/index.js +28 -0
  61. package/dist/errors/invalid-credentials.d.ts +1 -0
  62. package/dist/errors/invalid-credentials.js +3 -0
  63. package/dist/errors/invalid-foreign-key.d.ts +6 -0
  64. package/dist/errors/invalid-foreign-key.js +14 -0
  65. package/dist/errors/invalid-ip.d.ts +1 -0
  66. package/dist/errors/invalid-ip.js +3 -0
  67. package/dist/errors/invalid-otp.d.ts +1 -0
  68. package/dist/errors/invalid-otp.js +3 -0
  69. package/dist/errors/invalid-payload.d.ts +5 -0
  70. package/dist/errors/invalid-payload.js +4 -0
  71. package/dist/errors/invalid-provider-config.d.ts +5 -0
  72. package/dist/errors/invalid-provider-config.js +3 -0
  73. package/dist/errors/invalid-provider.d.ts +1 -0
  74. package/dist/errors/invalid-provider.js +3 -0
  75. package/dist/errors/invalid-query.d.ts +5 -0
  76. package/dist/errors/invalid-query.js +4 -0
  77. package/dist/errors/invalid-token.d.ts +1 -0
  78. package/dist/errors/invalid-token.js +3 -0
  79. package/dist/errors/method-not-allowed.d.ts +6 -0
  80. package/dist/errors/method-not-allowed.js +6 -0
  81. package/dist/errors/not-null-violation.d.ts +6 -0
  82. package/dist/errors/not-null-violation.js +14 -0
  83. package/dist/errors/range-not-satisfiable.d.ts +7 -0
  84. package/dist/errors/range-not-satisfiable.js +7 -0
  85. package/dist/errors/record-not-unique.d.ts +6 -0
  86. package/dist/errors/record-not-unique.js +14 -0
  87. package/dist/errors/route-not-found.d.ts +5 -0
  88. package/dist/errors/route-not-found.js +4 -0
  89. package/dist/errors/service-unavailable.d.ts +7 -0
  90. package/dist/errors/service-unavailable.js +4 -0
  91. package/dist/errors/token-expired.d.ts +1 -0
  92. package/dist/errors/token-expired.js +3 -0
  93. package/dist/errors/unexpected-response.d.ts +1 -0
  94. package/dist/errors/unexpected-response.js +3 -0
  95. package/dist/errors/unprocessable-content.d.ts +5 -0
  96. package/dist/errors/unprocessable-content.js +4 -0
  97. package/dist/errors/unsupported-media-type.d.ts +6 -0
  98. package/dist/errors/unsupported-media-type.js +4 -0
  99. package/dist/errors/user-suspended.d.ts +1 -0
  100. package/dist/errors/user-suspended.js +3 -0
  101. package/dist/errors/value-out-of-range.d.ts +6 -0
  102. package/dist/errors/value-out-of-range.js +14 -0
  103. package/dist/errors/value-too-long.d.ts +6 -0
  104. package/dist/errors/value-too-long.js +14 -0
  105. package/dist/extensions.js +0 -4
  106. package/dist/flows.js +6 -8
  107. package/dist/index.d.ts +0 -2
  108. package/dist/index.js +0 -2
  109. package/dist/messenger.js +4 -4
  110. package/dist/middleware/authenticate.js +1 -1
  111. package/dist/middleware/check-ip.js +2 -2
  112. package/dist/middleware/collection-exists.js +2 -2
  113. package/dist/middleware/error-handler.js +7 -7
  114. package/dist/middleware/graphql.js +11 -9
  115. package/dist/middleware/rate-limiter-global.d.ts +2 -2
  116. package/dist/middleware/rate-limiter-global.js +2 -3
  117. package/dist/middleware/rate-limiter-ip.d.ts +2 -2
  118. package/dist/middleware/rate-limiter-ip.js +2 -3
  119. package/dist/middleware/validate-batch.js +3 -4
  120. package/dist/rate-limiter.js +2 -9
  121. package/dist/services/activity.js +3 -2
  122. package/dist/services/assets.js +9 -10
  123. package/dist/services/authentication.js +12 -11
  124. package/dist/services/authorization.d.ts +1 -1
  125. package/dist/services/authorization.js +16 -16
  126. package/dist/services/collections.js +17 -16
  127. package/dist/services/fields.js +16 -14
  128. package/dist/services/files.js +7 -6
  129. package/dist/services/graphql/errors/execution.d.ts +6 -0
  130. package/dist/services/graphql/errors/execution.js +2 -0
  131. package/dist/services/graphql/errors/index.d.ts +2 -0
  132. package/dist/services/graphql/errors/index.js +2 -0
  133. package/dist/services/graphql/errors/validation.d.ts +6 -0
  134. package/dist/services/graphql/errors/validation.js +2 -0
  135. package/dist/services/graphql/index.d.ts +2 -2
  136. package/dist/services/graphql/index.js +30 -12
  137. package/dist/services/graphql/utils/process-error.js +3 -3
  138. package/dist/services/import-export.js +7 -7
  139. package/dist/services/index.d.ts +1 -0
  140. package/dist/services/index.js +1 -0
  141. package/dist/services/items.js +14 -13
  142. package/dist/services/mail/index.js +3 -3
  143. package/dist/services/meta.js +3 -3
  144. package/dist/services/payload.js +11 -7
  145. package/dist/services/relations.js +32 -22
  146. package/dist/services/revisions.js +3 -3
  147. package/dist/services/roles.js +10 -9
  148. package/dist/services/schema.js +5 -5
  149. package/dist/services/shares.js +4 -4
  150. package/dist/services/tfa.js +6 -6
  151. package/dist/services/translations.d.ts +2 -2
  152. package/dist/services/translations.js +4 -4
  153. package/dist/services/users.js +26 -29
  154. package/dist/services/utils.js +4 -4
  155. package/dist/synchronization.js +3 -3
  156. package/dist/types/items.d.ts +2 -2
  157. package/dist/utils/apply-diff.js +2 -2
  158. package/dist/utils/apply-query.js +17 -7
  159. package/dist/utils/get-accountability-for-role.js +1 -2
  160. package/dist/utils/get-accountability-for-token.js +3 -3
  161. package/dist/utils/get-column-path.js +5 -3
  162. package/dist/utils/get-column.js +3 -3
  163. package/dist/utils/get-service.d.ts +1 -1
  164. package/dist/utils/get-service.js +1 -1
  165. package/dist/utils/jwt.js +5 -5
  166. package/dist/utils/validate-diff.js +23 -9
  167. package/dist/utils/validate-keys.js +3 -3
  168. package/dist/utils/validate-query.d.ts +2 -0
  169. package/dist/utils/validate-query.js +27 -21
  170. package/dist/utils/validate-snapshot.js +11 -5
  171. package/dist/websocket/authenticate.js +12 -15
  172. package/dist/websocket/controllers/base.js +18 -15
  173. package/dist/websocket/controllers/graphql.js +2 -2
  174. package/dist/websocket/controllers/index.js +3 -7
  175. package/dist/websocket/controllers/rest.js +3 -3
  176. package/dist/websocket/{exceptions.d.ts → errors.d.ts} +5 -5
  177. package/dist/websocket/{exceptions.js → errors.js} +10 -10
  178. package/dist/websocket/handlers/items.js +5 -5
  179. package/dist/websocket/handlers/subscribe.js +8 -8
  180. package/package.json +15 -15
  181. package/dist/exceptions/content-too-large.d.ts +0 -4
  182. package/dist/exceptions/content-too-large.js +0 -6
  183. package/dist/exceptions/database/contains-null-values.d.ts +0 -9
  184. package/dist/exceptions/database/contains-null-values.js +0 -6
  185. package/dist/exceptions/database/invalid-foreign-key.d.ts +0 -10
  186. package/dist/exceptions/database/invalid-foreign-key.js +0 -11
  187. package/dist/exceptions/database/not-null-violation.d.ts +0 -9
  188. package/dist/exceptions/database/not-null-violation.js +0 -6
  189. package/dist/exceptions/database/record-not-unique.d.ts +0 -10
  190. package/dist/exceptions/database/record-not-unique.js +0 -11
  191. package/dist/exceptions/database/value-out-of-range.d.ts +0 -10
  192. package/dist/exceptions/database/value-out-of-range.js +0 -11
  193. package/dist/exceptions/database/value-too-long.d.ts +0 -9
  194. package/dist/exceptions/database/value-too-long.js +0 -11
  195. package/dist/exceptions/forbidden.d.ts +0 -6
  196. package/dist/exceptions/forbidden.js +0 -13
  197. package/dist/exceptions/graphql-validation.d.ts +0 -4
  198. package/dist/exceptions/graphql-validation.js +0 -6
  199. package/dist/exceptions/hit-rate-limit.d.ts +0 -9
  200. package/dist/exceptions/hit-rate-limit.js +0 -6
  201. package/dist/exceptions/illegal-asset-transformation.d.ts +0 -4
  202. package/dist/exceptions/illegal-asset-transformation.js +0 -6
  203. package/dist/exceptions/index.d.ts +0 -21
  204. package/dist/exceptions/index.js +0 -21
  205. package/dist/exceptions/invalid-config.d.ts +0 -4
  206. package/dist/exceptions/invalid-config.js +0 -6
  207. package/dist/exceptions/invalid-credentials.d.ts +0 -4
  208. package/dist/exceptions/invalid-credentials.js +0 -6
  209. package/dist/exceptions/invalid-ip.d.ts +0 -4
  210. package/dist/exceptions/invalid-ip.js +0 -6
  211. package/dist/exceptions/invalid-otp.d.ts +0 -4
  212. package/dist/exceptions/invalid-otp.js +0 -6
  213. package/dist/exceptions/invalid-payload.d.ts +0 -4
  214. package/dist/exceptions/invalid-payload.js +0 -6
  215. package/dist/exceptions/invalid-provider.d.ts +0 -4
  216. package/dist/exceptions/invalid-provider.js +0 -6
  217. package/dist/exceptions/invalid-query.d.ts +0 -4
  218. package/dist/exceptions/invalid-query.js +0 -6
  219. package/dist/exceptions/invalid-token.d.ts +0 -4
  220. package/dist/exceptions/invalid-token.js +0 -6
  221. package/dist/exceptions/method-not-allowed.d.ts +0 -8
  222. package/dist/exceptions/method-not-allowed.js +0 -6
  223. package/dist/exceptions/range-not-satisfiable.d.ts +0 -5
  224. package/dist/exceptions/range-not-satisfiable.js +0 -9
  225. package/dist/exceptions/route-not-found.d.ts +0 -4
  226. package/dist/exceptions/route-not-found.js +0 -6
  227. package/dist/exceptions/service-unavailable.d.ts +0 -9
  228. package/dist/exceptions/service-unavailable.js +0 -6
  229. package/dist/exceptions/token-expired.d.ts +0 -4
  230. package/dist/exceptions/token-expired.js +0 -6
  231. package/dist/exceptions/unexpected-response.d.ts +0 -4
  232. package/dist/exceptions/unexpected-response.js +0 -6
  233. package/dist/exceptions/unprocessable-entity.d.ts +0 -4
  234. package/dist/exceptions/unprocessable-entity.js +0 -6
  235. package/dist/exceptions/unsupported-media-type.d.ts +0 -4
  236. package/dist/exceptions/unsupported-media-type.js +0 -6
  237. package/dist/exceptions/user-suspended.d.ts +0 -4
  238. package/dist/exceptions/user-suspended.js +0 -6
  239. /package/dist/{exceptions/database → database/errors}/dialects/mssql.d.ts +0 -0
  240. /package/dist/{exceptions/database → database/errors}/dialects/mysql.d.ts +0 -0
  241. /package/dist/{exceptions/database → database/errors}/dialects/oracle.d.ts +0 -0
  242. /package/dist/{exceptions/database → database/errors}/dialects/postgres.d.ts +0 -0
  243. /package/dist/{exceptions/database → database/errors}/dialects/sqlite.d.ts +0 -0
  244. /package/dist/{exceptions/database → database/errors}/dialects/types.d.ts +0 -0
  245. /package/dist/{exceptions/database → database/errors}/dialects/types.js +0 -0
  246. /package/dist/{exceptions/database → database/errors}/translate.d.ts +0 -0
@@ -1,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -34,7 +35,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
34
35
  }
35
36
  }
36
37
  catch (error) {
37
- if (error instanceof ForbiddenException) {
38
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
38
39
  return next();
39
40
  }
40
41
  throw error;
@@ -96,7 +97,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
96
97
  res.locals['payload'] = { data: result };
97
98
  }
98
99
  catch (error) {
99
- if (error instanceof ForbiddenException) {
100
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
100
101
  return next();
101
102
  }
102
103
  throw error;
@@ -114,7 +115,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
114
115
  res.locals['payload'] = { data: record };
115
116
  }
116
117
  catch (error) {
117
- if (error instanceof ForbiddenException) {
118
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
118
119
  return next();
119
120
  }
120
121
  throw error;
@@ -1,5 +1,6 @@
1
1
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
2
+ import { isDirectusError } from '@directus/errors';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -34,7 +35,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
34
35
  }
35
36
  }
36
37
  catch (error) {
37
- if (error instanceof ForbiddenException) {
38
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
38
39
  return next();
39
40
  }
40
41
  throw error;
@@ -87,7 +88,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
87
88
  res.locals['payload'] = { data: result };
88
89
  }
89
90
  catch (error) {
90
- if (error instanceof ForbiddenException) {
91
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
91
92
  return next();
92
93
  }
93
94
  throw error;
@@ -105,7 +106,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
105
106
  res.locals['payload'] = { data: item || null };
106
107
  }
107
108
  catch (error) {
108
- if (error instanceof ForbiddenException) {
109
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
109
110
  return next();
110
111
  }
111
112
  throw error;
@@ -1,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -34,7 +35,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
34
35
  }
35
36
  }
36
37
  catch (error) {
37
- if (error instanceof ForbiddenException) {
38
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
38
39
  return next();
39
40
  }
40
41
  throw error;
@@ -87,7 +88,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
87
88
  res.locals['payload'] = { data: result };
88
89
  }
89
90
  catch (error) {
90
- if (error instanceof ForbiddenException) {
91
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
91
92
  return next();
92
93
  }
93
94
  throw error;
@@ -105,7 +106,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
105
106
  res.locals['payload'] = { data: item || null };
106
107
  }
107
108
  catch (error) {
108
- if (error instanceof ForbiddenException) {
109
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
109
110
  return next();
110
111
  }
111
112
  throw error;
@@ -1,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -34,7 +35,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
34
35
  }
35
36
  }
36
37
  catch (error) {
37
- if (error instanceof ForbiddenException) {
38
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
38
39
  return next();
39
40
  }
40
41
  throw error;
@@ -101,7 +102,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
101
102
  res.locals['payload'] = { data: result };
102
103
  }
103
104
  catch (error) {
104
- if (error instanceof ForbiddenException) {
105
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
105
106
  return next();
106
107
  }
107
108
  throw error;
@@ -119,7 +120,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
119
120
  res.locals['payload'] = { data: item || null };
120
121
  }
121
122
  catch (error) {
122
- if (error instanceof ForbiddenException) {
123
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
123
124
  return next();
124
125
  }
125
126
  throw error;
@@ -1,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -34,7 +35,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
34
35
  }
35
36
  }
36
37
  catch (error) {
37
- if (error instanceof ForbiddenException) {
38
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
38
39
  return next();
39
40
  }
40
41
  throw error;
@@ -96,7 +97,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
96
97
  res.locals['payload'] = { data: result };
97
98
  }
98
99
  catch (error) {
99
- if (error instanceof ForbiddenException) {
100
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
100
101
  return next();
101
102
  }
102
103
  throw error;
@@ -114,7 +115,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
114
115
  res.locals['payload'] = { data: record };
115
116
  }
116
117
  catch (error) {
117
- if (error instanceof ForbiddenException) {
118
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
118
119
  return next();
119
120
  }
120
121
  throw error;
@@ -1,6 +1,7 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
3
  import Joi from 'joi';
3
- import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js';
4
+ import { ErrorCode, InvalidPayloadError } from '../errors/index.js';
4
5
  import validateCollection from '../middleware/collection-exists.js';
5
6
  import { respond } from '../middleware/respond.js';
6
7
  import useCollection from '../middleware/use-collection.js';
@@ -53,7 +54,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
53
54
  });
54
55
  const { error } = newRelationSchema.validate(req.body);
55
56
  if (error) {
56
- throw new InvalidPayloadException(error.message);
57
+ throw new InvalidPayloadError({ reason: error.message });
57
58
  }
58
59
  await service.createOne(req.body);
59
60
  try {
@@ -61,7 +62,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
61
62
  res.locals['payload'] = { data: createdRelation || null };
62
63
  }
63
64
  catch (error) {
64
- if (error instanceof ForbiddenException) {
65
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
65
66
  return next();
66
67
  }
67
68
  throw error;
@@ -86,7 +87,7 @@ router.patch('/:collection/:field', validateCollection, asyncHandler(async (req,
86
87
  });
87
88
  const { error } = updateRelationSchema.validate(req.body);
88
89
  if (error) {
89
- throw new InvalidPayloadException(error.message);
90
+ throw new InvalidPayloadError({ reason: error.message });
90
91
  }
91
92
  await service.updateOne(req.params['collection'], req.params['field'], req.body);
92
93
  try {
@@ -94,7 +95,7 @@ router.patch('/:collection/:field', validateCollection, asyncHandler(async (req,
94
95
  res.locals['payload'] = { data: updatedField || null };
95
96
  }
96
97
  catch (error) {
97
- if (error instanceof ForbiddenException) {
98
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
98
99
  return next();
99
100
  }
100
101
  throw error;
@@ -1,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -34,7 +35,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
34
35
  }
35
36
  }
36
37
  catch (error) {
37
- if (error instanceof ForbiddenException) {
38
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
38
39
  return next();
39
40
  }
40
41
  throw error;
@@ -87,7 +88,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
87
88
  res.locals['payload'] = { data: result };
88
89
  }
89
90
  catch (error) {
90
- if (error instanceof ForbiddenException) {
91
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
91
92
  return next();
92
93
  }
93
94
  throw error;
@@ -105,7 +106,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
105
106
  res.locals['payload'] = { data: item || null };
106
107
  }
107
108
  catch (error) {
108
- if (error instanceof ForbiddenException) {
109
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
109
110
  return next();
110
111
  }
111
112
  throw error;
@@ -2,7 +2,7 @@ import { parseJSON } from '@directus/utils';
2
2
  import Busboy from 'busboy';
3
3
  import express from 'express';
4
4
  import { load as loadYaml } from 'js-yaml';
5
- import { InvalidPayloadException, UnsupportedMediaTypeException } from '../exceptions/index.js';
5
+ import { InvalidPayloadError, UnsupportedMediaTypeError } from '../errors/index.js';
6
6
  import logger from '../logger.js';
7
7
  import { respond } from '../middleware/respond.js';
8
8
  import { SchemaService } from '../services/schema.js';
@@ -18,13 +18,13 @@ router.get('/snapshot', asyncHandler(async (req, res, next) => {
18
18
  const schemaMultipartHandler = (req, res, next) => {
19
19
  if (req.is('application/json')) {
20
20
  if (Object.keys(req.body).length === 0) {
21
- throw new InvalidPayloadException(`No data was included in the body`);
21
+ throw new InvalidPayloadError({ reason: `No data was included in the body` });
22
22
  }
23
23
  res.locals['upload'] = req.body;
24
24
  return next();
25
25
  }
26
26
  if (!req.is('multipart/form-data')) {
27
- throw new UnsupportedMediaTypeException(`Unsupported Content-Type header`);
27
+ throw new UnsupportedMediaTypeError({ mediaType: req.headers['content-type'], where: 'Content-Type header' });
28
28
  }
29
29
  const headers = req.headers['content-type']
30
30
  ? req.headers
@@ -37,7 +37,7 @@ const schemaMultipartHandler = (req, res, next) => {
37
37
  let upload = null;
38
38
  busboy.on('file', async (_, fileStream, { mimeType }) => {
39
39
  if (isFileIncluded)
40
- return next(new InvalidPayloadException(`More than one file was included in the body`));
40
+ return next(new InvalidPayloadError({ reason: `More than one file was included in the body` }));
41
41
  isFileIncluded = true;
42
42
  const { readableStreamToString } = await import('@directus/utils/node');
43
43
  try {
@@ -48,7 +48,7 @@ const schemaMultipartHandler = (req, res, next) => {
48
48
  }
49
49
  catch (err) {
50
50
  logger.warn(err);
51
- throw new InvalidPayloadException('The provided JSON is invalid.');
51
+ throw new InvalidPayloadError({ reason: 'The provided JSON is invalid' });
52
52
  }
53
53
  }
54
54
  else {
@@ -57,11 +57,11 @@ const schemaMultipartHandler = (req, res, next) => {
57
57
  }
58
58
  catch (err) {
59
59
  logger.warn(err);
60
- throw new InvalidPayloadException('The provided YAML is invalid.');
60
+ throw new InvalidPayloadError({ reason: 'The provided YAML is invalid' });
61
61
  }
62
62
  }
63
63
  if (!upload) {
64
- throw new InvalidPayloadException(`No file was included in the body`);
64
+ throw new InvalidPayloadError({ reason: `No file was included in the body` });
65
65
  }
66
66
  res.locals['upload'] = upload;
67
67
  return next();
@@ -73,7 +73,7 @@ const schemaMultipartHandler = (req, res, next) => {
73
73
  busboy.on('error', (error) => next(error));
74
74
  busboy.on('close', () => {
75
75
  if (!isFileIncluded)
76
- return next(new InvalidPayloadException(`No file was included in the body`));
76
+ return next(new InvalidPayloadError({ reason: `No file was included in the body` }));
77
77
  });
78
78
  req.pipe(busboy);
79
79
  };
@@ -1,6 +1,6 @@
1
1
  import { format } from 'date-fns';
2
2
  import { Router } from 'express';
3
- import { RouteNotFoundException } from '../exceptions/index.js';
3
+ import { RouteNotFoundError } from '../errors/index.js';
4
4
  import { respond } from '../middleware/respond.js';
5
5
  import { ServerService } from '../services/server.js';
6
6
  import { SpecificationService } from '../services/specifications.js';
@@ -25,7 +25,7 @@ router.get('/specs/graphql/:scope?', asyncHandler(async (req, res) => {
25
25
  });
26
26
  const scope = req.params['scope'] || 'items';
27
27
  if (['items', 'system'].includes(scope) === false)
28
- throw new RouteNotFoundException(req.path);
28
+ throw new RouteNotFoundError({ path: req.path });
29
29
  const info = await serverService.serverInfo();
30
30
  const result = await service.graphql.generate(scope);
31
31
  const filename = info['project'].project_name + '_' + format(new Date(), 'yyyy-MM-dd') + '.graphql';
@@ -1,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { SettingsService } from '../services/settings.js';
@@ -26,7 +27,7 @@ router.patch('/', asyncHandler(async (req, res, next) => {
26
27
  res.locals['payload'] = { data: record || null };
27
28
  }
28
29
  catch (error) {
29
- if (error instanceof ForbiddenException) {
30
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
30
31
  return next();
31
32
  }
32
33
  throw error;
@@ -1,8 +1,9 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
3
  import Joi from 'joi';
3
4
  import { COOKIE_OPTIONS, UUID_REGEX } from '../constants.js';
4
5
  import env from '../env.js';
5
- import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js';
6
+ import { ErrorCode, InvalidPayloadError } from '../errors/index.js';
6
7
  import { respond } from '../middleware/respond.js';
7
8
  import useCollection from '../middleware/use-collection.js';
8
9
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -22,7 +23,7 @@ router.post('/auth', asyncHandler(async (req, res, next) => {
22
23
  });
23
24
  const { error } = sharedLoginSchema.validate(req.body);
24
25
  if (error) {
25
- throw new InvalidPayloadException(error.message);
26
+ throw new InvalidPayloadError({ reason: error.message });
26
27
  }
27
28
  const { accessToken, refreshToken, expires } = await service.login(req.body);
28
29
  res.cookie(env['REFRESH_TOKEN_COOKIE_NAME'], refreshToken, COOKIE_OPTIONS);
@@ -40,7 +41,7 @@ router.post('/invite', asyncHandler(async (req, _res, next) => {
40
41
  });
41
42
  const { error } = sharedInviteSchema.validate(req.body);
42
43
  if (error) {
43
- throw new InvalidPayloadException(error.message);
44
+ throw new InvalidPayloadError({ reason: error.message });
44
45
  }
45
46
  await service.invite(req.body);
46
47
  return next();
@@ -70,7 +71,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
70
71
  }
71
72
  }
72
73
  catch (error) {
73
- if (error instanceof ForbiddenException) {
74
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
74
75
  return next();
75
76
  }
76
77
  throw error;
@@ -160,7 +161,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
160
161
  res.locals['payload'] = { data: result };
161
162
  }
162
163
  catch (error) {
163
- if (error instanceof ForbiddenException) {
164
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
164
165
  return next();
165
166
  }
166
167
  throw error;
@@ -178,7 +179,7 @@ router.patch(`/:pk(${UUID_REGEX})`, asyncHandler(async (req, res, next) => {
178
179
  res.locals['payload'] = { data: item || null };
179
180
  }
180
181
  catch (error) {
181
- if (error instanceof ForbiddenException) {
182
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
182
183
  return next();
183
184
  }
184
185
  throw error;
@@ -1,10 +1,11 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException } from '../exceptions/index.js';
3
+ import { ErrorCode } from '../errors/index.js';
3
4
  import { respond } from '../middleware/respond.js';
4
5
  import useCollection from '../middleware/use-collection.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
6
- import { TranslationsService } from '../services/translations.js';
7
7
  import { MetaService } from '../services/meta.js';
8
+ import { TranslationsService } from '../services/translations.js';
8
9
  import asyncHandler from '../utils/async-handler.js';
9
10
  import { sanitizeQuery } from '../utils/sanitize-query.js';
10
11
  const router = express.Router();
@@ -34,7 +35,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
34
35
  }
35
36
  }
36
37
  catch (error) {
37
- if (error instanceof ForbiddenException) {
38
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
38
39
  return next();
39
40
  }
40
41
  throw error;
@@ -96,7 +97,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
96
97
  res.locals['payload'] = { data: result || null };
97
98
  }
98
99
  catch (error) {
99
- if (error instanceof ForbiddenException) {
100
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
100
101
  return next();
101
102
  }
102
103
  throw error;
@@ -114,7 +115,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
114
115
  res.locals['payload'] = { data: record || null };
115
116
  }
116
117
  catch (error) {
117
- if (error instanceof ForbiddenException) {
118
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
118
119
  return next();
119
120
  }
120
121
  throw error;
@@ -1,6 +1,7 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
3
  import Joi from 'joi';
3
- import { ForbiddenException, InvalidCredentialsException, InvalidPayloadException } from '../exceptions/index.js';
4
+ import { ErrorCode, ForbiddenError, InvalidCredentialsError, InvalidPayloadError } from '../errors/index.js';
4
5
  import { respond } from '../middleware/respond.js';
5
6
  import useCollection from '../middleware/use-collection.js';
6
7
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -38,7 +39,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
38
39
  }
39
40
  }
40
41
  catch (error) {
41
- if (error instanceof ForbiddenException) {
42
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
42
43
  return next();
43
44
  }
44
45
  throw error;
@@ -75,7 +76,7 @@ router.get('/me', asyncHandler(async (req, res, next) => {
75
76
  return next();
76
77
  }
77
78
  if (!req.accountability?.user) {
78
- throw new InvalidCredentialsException();
79
+ throw new InvalidCredentialsError();
79
80
  }
80
81
  const service = new UsersService({
81
82
  accountability: req.accountability,
@@ -86,7 +87,7 @@ router.get('/me', asyncHandler(async (req, res, next) => {
86
87
  res.locals['payload'] = { data: item || null };
87
88
  }
88
89
  catch (error) {
89
- if (error instanceof ForbiddenException) {
90
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
90
91
  res.locals['payload'] = { data: { id: req.accountability.user } };
91
92
  return next();
92
93
  }
@@ -107,7 +108,7 @@ router.get('/:pk', asyncHandler(async (req, res, next) => {
107
108
  }), respond);
108
109
  router.patch('/me', asyncHandler(async (req, res, next) => {
109
110
  if (!req.accountability?.user) {
110
- throw new InvalidCredentialsException();
111
+ throw new InvalidCredentialsError();
111
112
  }
112
113
  const service = new UsersService({
113
114
  accountability: req.accountability,
@@ -120,10 +121,10 @@ router.patch('/me', asyncHandler(async (req, res, next) => {
120
121
  }), respond);
121
122
  router.patch('/me/track/page', asyncHandler(async (req, _res, next) => {
122
123
  if (!req.accountability?.user) {
123
- throw new InvalidCredentialsException();
124
+ throw new InvalidCredentialsError();
124
125
  }
125
126
  if (!req.body.last_page) {
126
- throw new InvalidPayloadException(`"last_page" key is required.`);
127
+ throw new InvalidPayloadError({ reason: `"last_page" key is required` });
127
128
  }
128
129
  const service = new UsersService({ schema: req.schema });
129
130
  await service.updateOne(req.accountability.user, { last_page: req.body.last_page }, { autoPurgeCache: false });
@@ -150,7 +151,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
150
151
  res.locals['payload'] = { data: result };
151
152
  }
152
153
  catch (error) {
153
- if (error instanceof ForbiddenException) {
154
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
154
155
  return next();
155
156
  }
156
157
  throw error;
@@ -168,7 +169,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
168
169
  res.locals['payload'] = { data: item || null };
169
170
  }
170
171
  catch (error) {
171
- if (error instanceof ForbiddenException) {
172
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
172
173
  return next();
173
174
  }
174
175
  throw error;
@@ -208,7 +209,7 @@ const inviteSchema = Joi.object({
208
209
  router.post('/invite', asyncHandler(async (req, _res, next) => {
209
210
  const { error } = inviteSchema.validate(req.body);
210
211
  if (error)
211
- throw new InvalidPayloadException(error.message);
212
+ throw new InvalidPayloadError({ reason: error.message });
212
213
  const service = new UsersService({
213
214
  accountability: req.accountability,
214
215
  schema: req.schema,
@@ -223,7 +224,7 @@ const acceptInviteSchema = Joi.object({
223
224
  router.post('/invite/accept', asyncHandler(async (req, _res, next) => {
224
225
  const { error } = acceptInviteSchema.validate(req.body);
225
226
  if (error)
226
- throw new InvalidPayloadException(error.message);
227
+ throw new InvalidPayloadError({ reason: error.message });
227
228
  const service = new UsersService({
228
229
  accountability: req.accountability,
229
230
  schema: req.schema,
@@ -233,10 +234,10 @@ router.post('/invite/accept', asyncHandler(async (req, _res, next) => {
233
234
  }), respond);
234
235
  router.post('/me/tfa/generate/', asyncHandler(async (req, res, next) => {
235
236
  if (!req.accountability?.user) {
236
- throw new InvalidCredentialsException();
237
+ throw new InvalidCredentialsError();
237
238
  }
238
239
  if (!req.body.password) {
239
- throw new InvalidPayloadException(`"password" is required`);
240
+ throw new InvalidPayloadError({ reason: `"password" is required` });
240
241
  }
241
242
  const service = new TFAService({
242
243
  accountability: req.accountability,
@@ -253,13 +254,13 @@ router.post('/me/tfa/generate/', asyncHandler(async (req, res, next) => {
253
254
  }), respond);
254
255
  router.post('/me/tfa/enable/', asyncHandler(async (req, _res, next) => {
255
256
  if (!req.accountability?.user) {
256
- throw new InvalidCredentialsException();
257
+ throw new InvalidCredentialsError();
257
258
  }
258
259
  if (!req.body.secret) {
259
- throw new InvalidPayloadException(`"secret" is required`);
260
+ throw new InvalidPayloadError({ reason: `"secret" is required` });
260
261
  }
261
262
  if (!req.body.otp) {
262
- throw new InvalidPayloadException(`"otp" is required`);
263
+ throw new InvalidPayloadError({ reason: `"otp" is required` });
263
264
  }
264
265
  // Override permissions only when enforce TFA is enabled in role
265
266
  if (req.accountability.role) {
@@ -297,10 +298,10 @@ router.post('/me/tfa/enable/', asyncHandler(async (req, _res, next) => {
297
298
  }), respond);
298
299
  router.post('/me/tfa/disable', asyncHandler(async (req, _res, next) => {
299
300
  if (!req.accountability?.user) {
300
- throw new InvalidCredentialsException();
301
+ throw new InvalidCredentialsError();
301
302
  }
302
303
  if (!req.body.otp) {
303
- throw new InvalidPayloadException(`"otp" is required`);
304
+ throw new InvalidPayloadError({ reason: `"otp" is required` });
304
305
  }
305
306
  // Override permissions only when enforce TFA is enabled in role
306
307
  if (req.accountability.role) {
@@ -335,17 +336,17 @@ router.post('/me/tfa/disable', asyncHandler(async (req, _res, next) => {
335
336
  });
336
337
  const otpValid = await service.verifyOTP(req.accountability.user, req.body.otp);
337
338
  if (otpValid === false) {
338
- throw new InvalidPayloadException(`"otp" is invalid`);
339
+ throw new InvalidPayloadError({ reason: `"otp" is invalid` });
339
340
  }
340
341
  await service.disableTFA(req.accountability.user);
341
342
  return next();
342
343
  }), respond);
343
344
  router.post('/:pk/tfa/disable', asyncHandler(async (req, _res, next) => {
344
345
  if (!req.accountability?.user) {
345
- throw new InvalidCredentialsException();
346
+ throw new InvalidCredentialsError();
346
347
  }
347
348
  if (!req.accountability.admin || !req.params['pk']) {
348
- throw new ForbiddenException();
349
+ throw new ForbiddenError();
349
350
  }
350
351
  const service = new TFAService({
351
352
  accountability: req.accountability,