@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
@@ -1,7 +1,8 @@
1
1
  import { Action } from '@directus/constants';
2
+ import { isDirectusError } from '@directus/errors';
2
3
  import express from 'express';
3
4
  import Joi from 'joi';
4
- import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js';
5
+ import { ErrorCode, ForbiddenError, InvalidPayloadError } from '../errors/index.js';
5
6
  import { respond } from '../middleware/respond.js';
6
7
  import useCollection from '../middleware/use-collection.js';
7
8
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -62,7 +63,7 @@ router.post('/comment', asyncHandler(async (req, res, next) => {
62
63
  });
63
64
  const { error } = createCommentSchema.validate(req.body);
64
65
  if (error) {
65
- throw new InvalidPayloadException(error.message);
66
+ throw new InvalidPayloadError({ reason: error.message });
66
67
  }
67
68
  const primaryKey = await service.createOne({
68
69
  ...req.body,
@@ -79,7 +80,7 @@ router.post('/comment', asyncHandler(async (req, res, next) => {
79
80
  };
80
81
  }
81
82
  catch (error) {
82
- if (error instanceof ForbiddenException) {
83
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
83
84
  return next();
84
85
  }
85
86
  throw error;
@@ -96,7 +97,7 @@ router.patch('/comment/:pk', asyncHandler(async (req, res, next) => {
96
97
  });
97
98
  const { error } = updateCommentSchema.validate(req.body);
98
99
  if (error) {
99
- throw new InvalidPayloadException(error.message);
100
+ throw new InvalidPayloadError({ reason: error.message });
100
101
  }
101
102
  const primaryKey = await service.updateOne(req.params['pk'], req.body);
102
103
  try {
@@ -106,7 +107,7 @@ router.patch('/comment/:pk', asyncHandler(async (req, res, next) => {
106
107
  };
107
108
  }
108
109
  catch (error) {
109
- if (error instanceof ForbiddenException) {
110
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
110
111
  return next();
111
112
  }
112
113
  throw error;
@@ -123,7 +124,7 @@ router.delete('/comment/:pk', asyncHandler(async (req, _res, next) => {
123
124
  });
124
125
  const item = await adminService.readOne(req.params['pk'], { fields: ['action'] });
125
126
  if (!item || item['action'] !== Action.COMMENT) {
126
- throw new ForbiddenException();
127
+ throw new ForbiddenError();
127
128
  }
128
129
  await service.deleteOne(req.params['pk']);
129
130
  return next();
@@ -5,7 +5,7 @@ import { merge, pick } from 'lodash-es';
5
5
  import { ASSET_TRANSFORM_QUERY_KEYS, SYSTEM_ASSET_ALLOW_LIST } from '../constants.js';
6
6
  import getDatabase from '../database/index.js';
7
7
  import env from '../env.js';
8
- import { InvalidQueryException, RangeNotSatisfiableException } from '../exceptions/index.js';
8
+ import { InvalidQueryError, RangeNotSatisfiableError } from '../errors/index.js';
9
9
  import logger from '../logger.js';
10
10
  import useCollection from '../middleware/use-collection.js';
11
11
  import { AssetsService } from '../services/assets.js';
@@ -33,7 +33,9 @@ asyncHandler(async (req, res, next) => {
33
33
  const assetSettings = savedAssetSettings || defaults;
34
34
  const transformation = pick(req.query, ASSET_TRANSFORM_QUERY_KEYS);
35
35
  if ('key' in transformation && Object.keys(transformation).length > 1) {
36
- throw new InvalidQueryException(`You can't combine the "key" query parameter with any other transformation.`);
36
+ throw new InvalidQueryError({
37
+ reason: `You can't combine the "key" query parameter with any other transformation`,
38
+ });
37
39
  }
38
40
  if ('transforms' in transformation) {
39
41
  let transforms;
@@ -42,21 +44,29 @@ asyncHandler(async (req, res, next) => {
42
44
  transforms = parseJSON(transformation['transforms']);
43
45
  }
44
46
  catch {
45
- throw new InvalidQueryException(`"transforms" Parameter needs to be a JSON array of allowed transformations.`);
47
+ throw new InvalidQueryError({
48
+ reason: `"transforms" Parameter needs to be a JSON array of allowed transformations`,
49
+ });
46
50
  }
47
51
  // Check if it is actually an array.
48
52
  if (!Array.isArray(transforms)) {
49
- throw new InvalidQueryException(`"transforms" Parameter needs to be a JSON array of allowed transformations.`);
53
+ throw new InvalidQueryError({
54
+ reason: `"transforms" Parameter needs to be a JSON array of allowed transformations`,
55
+ });
50
56
  }
51
57
  // Check against ASSETS_TRANSFORM_MAX_OPERATIONS
52
58
  if (transforms.length > Number(env['ASSETS_TRANSFORM_MAX_OPERATIONS'])) {
53
- throw new InvalidQueryException(`"transforms" Parameter is only allowed ${env['ASSETS_TRANSFORM_MAX_OPERATIONS']} transformations.`);
59
+ throw new InvalidQueryError({
60
+ reason: `"transforms" Parameter is only allowed ${env['ASSETS_TRANSFORM_MAX_OPERATIONS']} transformations`,
61
+ });
54
62
  }
55
63
  // Check the transformations are valid
56
64
  transforms.forEach((transform) => {
57
65
  const name = transform[0];
58
66
  if (!TransformationMethods.includes(name)) {
59
- throw new InvalidQueryException(`"transforms" Parameter does not allow "${name}" as a transformation.`);
67
+ throw new InvalidQueryError({
68
+ reason: `"transforms" Parameter does not allow "${name}" as a transformation`,
69
+ });
60
70
  }
61
71
  });
62
72
  transformation['transforms'] = transforms;
@@ -75,19 +85,19 @@ asyncHandler(async (req, res, next) => {
75
85
  }
76
86
  if (assetSettings.storage_asset_transform === 'all') {
77
87
  if (transformation['key'] && allKeys.includes(transformation['key']) === false) {
78
- throw new InvalidQueryException(`Key "${transformation['key']}" isn't configured.`);
88
+ throw new InvalidQueryError({ reason: `Key "${transformation['key']}" isn't configured` });
79
89
  }
80
90
  return next();
81
91
  }
82
92
  else if (assetSettings.storage_asset_transform === 'presets') {
83
93
  if (allKeys.includes(transformation['key']))
84
94
  return next();
85
- throw new InvalidQueryException(`Only configured presets can be used in asset generation.`);
95
+ throw new InvalidQueryError({ reason: `Only configured presets can be used in asset generation` });
86
96
  }
87
97
  else {
88
98
  if (transformation['key'] && systemKeys.includes(transformation['key']))
89
99
  return next();
90
- throw new InvalidQueryException(`Dynamic asset generation has been disabled for this project.`);
100
+ throw new InvalidQueryError({ reason: `Dynamic asset generation has been disabled for this project` });
91
101
  }
92
102
  }), asyncHandler(async (req, res, next) => {
93
103
  const helmet = await import('helmet');
@@ -123,16 +133,19 @@ asyncHandler(async (req, res) => {
123
133
  if (req.headers.range) {
124
134
  const rangeParts = /bytes=([0-9]*)-([0-9]*)/.exec(req.headers.range);
125
135
  if (rangeParts && rangeParts.length > 1) {
126
- range = {};
136
+ range = {
137
+ start: undefined,
138
+ end: undefined,
139
+ };
127
140
  if (rangeParts[1]) {
128
141
  range.start = Number(rangeParts[1]);
129
142
  if (Number.isNaN(range.start))
130
- throw new RangeNotSatisfiableException(range);
143
+ throw new RangeNotSatisfiableError({ range });
131
144
  }
132
145
  if (rangeParts[2]) {
133
146
  range.end = Number(rangeParts[2]);
134
147
  if (Number.isNaN(range.end))
135
- throw new RangeNotSatisfiableException(range);
148
+ throw new RangeNotSatisfiableError({ range });
136
149
  }
137
150
  }
138
151
  }
@@ -1,8 +1,9 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import { Router } from 'express';
2
3
  import { createLDAPAuthRouter, createLocalAuthRouter, createOAuth2AuthRouter, createOpenIDAuthRouter, createSAMLAuthRouter, } from '../auth/drivers/index.js';
3
4
  import { COOKIE_OPTIONS, DEFAULT_AUTH_PROVIDER } from '../constants.js';
4
5
  import env from '../env.js';
5
- import { InvalidPayloadException } from '../exceptions/index.js';
6
+ import { ErrorCode, InvalidPayloadError } from '../errors/index.js';
6
7
  import logger from '../logger.js';
7
8
  import { respond } from '../middleware/respond.js';
8
9
  import { AuthenticationService } from '../services/authentication.js';
@@ -57,7 +58,7 @@ router.post('/refresh', asyncHandler(async (req, res, next) => {
57
58
  });
58
59
  const currentRefreshToken = req.body.refresh_token || req.cookies[env['REFRESH_TOKEN_COOKIE_NAME']];
59
60
  if (!currentRefreshToken) {
60
- throw new InvalidPayloadException(`"refresh_token" is required in either the JSON payload or Cookie`);
61
+ throw new InvalidPayloadError({ reason: `"refresh_token" is required in either the JSON payload or Cookie` });
61
62
  }
62
63
  const mode = req.body.mode || (req.body.refresh_token ? 'json' : 'cookie');
63
64
  const { accessToken, refreshToken, expires } = await authenticationService.refresh(currentRefreshToken);
@@ -90,7 +91,7 @@ router.post('/logout', asyncHandler(async (req, res, next) => {
90
91
  });
91
92
  const currentRefreshToken = req.body.refresh_token || req.cookies[env['REFRESH_TOKEN_COOKIE_NAME']];
92
93
  if (!currentRefreshToken) {
93
- throw new InvalidPayloadException(`"refresh_token" is required in either the JSON payload or Cookie`);
94
+ throw new InvalidPayloadError({ reason: `"refresh_token" is required in either the JSON payload or Cookie` });
94
95
  }
95
96
  await authenticationService.logout(currentRefreshToken);
96
97
  if (req.cookies[env['REFRESH_TOKEN_COOKIE_NAME']]) {
@@ -105,7 +106,7 @@ router.post('/logout', asyncHandler(async (req, res, next) => {
105
106
  }), respond);
106
107
  router.post('/password/request', asyncHandler(async (req, _res, next) => {
107
108
  if (typeof req.body.email !== 'string') {
108
- throw new InvalidPayloadException(`"email" field is required.`);
109
+ throw new InvalidPayloadError({ reason: `"email" field is required` });
109
110
  }
110
111
  const accountability = {
111
112
  ip: getIPFromReq(req),
@@ -123,7 +124,7 @@ router.post('/password/request', asyncHandler(async (req, _res, next) => {
123
124
  return next();
124
125
  }
125
126
  catch (err) {
126
- if (err instanceof InvalidPayloadException) {
127
+ if (isDirectusError(err, ErrorCode.InvalidPayload)) {
127
128
  throw err;
128
129
  }
129
130
  else {
@@ -134,10 +135,10 @@ router.post('/password/request', asyncHandler(async (req, _res, next) => {
134
135
  }), respond);
135
136
  router.post('/password/reset', asyncHandler(async (req, _res, next) => {
136
137
  if (typeof req.body.token !== 'string') {
137
- throw new InvalidPayloadException(`"token" field is required.`);
138
+ throw new InvalidPayloadError({ reason: `"token" field is required` });
138
139
  }
139
140
  if (typeof req.body.password !== 'string') {
140
- throw new InvalidPayloadException(`"password" field is required.`);
141
+ throw new InvalidPayloadError({ reason: `"password" field is required` });
141
142
  }
142
143
  const accountability = {
143
144
  ip: getIPFromReq(req),
@@ -1,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import { Router } 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 { validateBatch } from '../middleware/validate-batch.js';
5
6
  import { CollectionsService } from '../services/collections.js';
@@ -65,7 +66,7 @@ router.patch('/', asyncHandler(async (req, res, next) => {
65
66
  res.locals['payload'] = { data: collections || null };
66
67
  }
67
68
  catch (error) {
68
- if (error instanceof ForbiddenException) {
69
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
69
70
  return next();
70
71
  }
71
72
  throw error;
@@ -83,7 +84,7 @@ router.patch('/:collection', asyncHandler(async (req, res, next) => {
83
84
  res.locals['payload'] = { data: collection || null };
84
85
  }
85
86
  catch (error) {
86
- if (error instanceof ForbiddenException) {
87
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
87
88
  return next();
88
89
  }
89
90
  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 { EXTENSION_TYPES } from '@directus/constants';
2
2
  import { depluralize, isIn } from '@directus/utils';
3
3
  import { Router } from 'express';
4
4
  import env from '../env.js';
5
- import { RouteNotFoundException } from '../exceptions/index.js';
5
+ import { RouteNotFoundError } from '../errors/index.js';
6
6
  import { getExtensionManager } from '../extensions.js';
7
7
  import { respond } from '../middleware/respond.js';
8
8
  import asyncHandler from '../utils/async-handler.js';
@@ -12,7 +12,7 @@ const router = Router();
12
12
  router.get('/:type', asyncHandler(async (req, res, next) => {
13
13
  const type = depluralize(req.params['type']);
14
14
  if (!isIn(type, EXTENSION_TYPES)) {
15
- throw new RouteNotFoundException(req.path);
15
+ throw new RouteNotFoundError({ path: req.path });
16
16
  }
17
17
  const extensionManager = getExtensionManager();
18
18
  const extensions = extensionManager.getExtensionsList(type);
@@ -32,7 +32,7 @@ router.get('/sources/:chunk', asyncHandler(async (req, res) => {
32
32
  source = extensionManager.getAppExtensionChunk(chunk);
33
33
  }
34
34
  if (source === null) {
35
- throw new RouteNotFoundException(req.path);
35
+ throw new RouteNotFoundError({ path: req.path });
36
36
  }
37
37
  res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
38
38
  res.setHeader('Cache-Control', getCacheControlHeader(req, getMilliseconds(env['EXTENSIONS_CACHE_TTL']), false, false));
@@ -1,8 +1,9 @@
1
1
  import { TYPES } from '@directus/constants';
2
+ import { isDirectusError } from '@directus/errors';
2
3
  import { Router } from 'express';
3
4
  import Joi from 'joi';
4
5
  import { ALIAS_TYPES } from '../constants.js';
5
- import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js';
6
+ import { ErrorCode, InvalidPayloadError } from '../errors/index.js';
6
7
  import validateCollection from '../middleware/collection-exists.js';
7
8
  import { respond } from '../middleware/respond.js';
8
9
  import useCollection from '../middleware/use-collection.js';
@@ -60,7 +61,7 @@ router.post('/:collection', validateCollection, asyncHandler(async (req, res, ne
60
61
  });
61
62
  const { error } = newFieldSchema.validate(req.body);
62
63
  if (error) {
63
- throw new InvalidPayloadException(error.message);
64
+ throw new InvalidPayloadError({ reason: error.message });
64
65
  }
65
66
  const field = req.body;
66
67
  await service.createField(req.params['collection'], field);
@@ -69,7 +70,7 @@ router.post('/:collection', validateCollection, asyncHandler(async (req, res, ne
69
70
  res.locals['payload'] = { data: createdField || null };
70
71
  }
71
72
  catch (error) {
72
- if (error instanceof ForbiddenException) {
73
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
73
74
  return next();
74
75
  }
75
76
  throw error;
@@ -82,7 +83,7 @@ router.patch('/:collection', validateCollection, asyncHandler(async (req, res, n
82
83
  schema: req.schema,
83
84
  });
84
85
  if (Array.isArray(req.body) === false) {
85
- throw new InvalidPayloadException('Submitted body has to be an array.');
86
+ throw new InvalidPayloadError({ reason: 'Submitted body has to be an array' });
86
87
  }
87
88
  for (const field of req.body) {
88
89
  await service.updateField(req.params['collection'], field);
@@ -96,7 +97,7 @@ router.patch('/:collection', validateCollection, asyncHandler(async (req, res, n
96
97
  }
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;
@@ -123,10 +124,10 @@ router.patch('/:collection/:field', validateCollection, asyncHandler(async (req,
123
124
  });
124
125
  const { error } = updateSchema.validate(req.body);
125
126
  if (error) {
126
- throw new InvalidPayloadException(error.message);
127
+ throw new InvalidPayloadError({ reason: error.message });
127
128
  }
128
129
  if (req.body.schema && !req.body.type) {
129
- throw new InvalidPayloadException(`You need to provide "type" when providing "schema".`);
130
+ throw new InvalidPayloadError({ reason: `You need to provide "type" when providing "schema"` });
130
131
  }
131
132
  const fieldData = req.body;
132
133
  if (!fieldData.field)
@@ -137,7 +138,7 @@ router.patch('/:collection/:field', validateCollection, asyncHandler(async (req,
137
138
  res.locals['payload'] = { data: updatedField || null };
138
139
  }
139
140
  catch (error) {
140
- if (error instanceof ForbiddenException) {
141
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
141
142
  return next();
142
143
  }
143
144
  throw error;
@@ -1,3 +1,4 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import formatTitle from '@directus/format-title';
2
3
  import { toArray } from '@directus/utils';
3
4
  import Busboy from 'busboy';
@@ -7,8 +8,7 @@ import Joi from 'joi';
7
8
  import { minimatch } from 'minimatch';
8
9
  import path from 'path';
9
10
  import env from '../env.js';
10
- import { ContentTooLargeException } from '../exceptions/content-too-large.js';
11
- import { ForbiddenException, InvalidPayloadException } from '../exceptions/index.js';
11
+ import { ContentTooLargeError, ErrorCode, InvalidPayloadError } from '../errors/index.js';
12
12
  import { respond } from '../middleware/respond.js';
13
13
  import useCollection from '../middleware/use-collection.js';
14
14
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -64,12 +64,12 @@ export const multipartHandler = (req, res, next) => {
64
64
  });
65
65
  busboy.on('file', async (_fieldname, fileStream, { filename, mimeType }) => {
66
66
  if (!filename) {
67
- return busboy.emit('error', new InvalidPayloadException(`File is missing filename`));
67
+ return busboy.emit('error', new InvalidPayloadError({ reason: `File is missing filename` }));
68
68
  }
69
69
  const allowedPatterns = toArray(env['FILES_MIME_TYPE_ALLOW_LIST']);
70
70
  const mimeTypeAllowed = allowedPatterns.some((pattern) => minimatch(mimeType, pattern));
71
71
  if (mimeTypeAllowed === false) {
72
- return busboy.emit('error', new InvalidPayloadException(`File is of invalid content type`));
72
+ return busboy.emit('error', new InvalidPayloadError({ reason: `File is of invalid content type` }));
73
73
  }
74
74
  fileCount++;
75
75
  if (!existingPrimaryKey) {
@@ -86,7 +86,7 @@ export const multipartHandler = (req, res, next) => {
86
86
  // Clear the payload for the next to-be-uploaded file
87
87
  payload = {};
88
88
  fileStream.on('limit', () => {
89
- const error = new ContentTooLargeException(`Uploaded file is too large`);
89
+ const error = new ContentTooLargeError();
90
90
  next(error);
91
91
  });
92
92
  try {
@@ -109,7 +109,7 @@ export const multipartHandler = (req, res, next) => {
109
109
  function tryDone() {
110
110
  if (savedFiles.length === fileCount) {
111
111
  if (fileCount === 0) {
112
- return next(new InvalidPayloadException(`No files were included in the body`));
112
+ return next(new InvalidPayloadError({ reason: `No files were included in the body` }));
113
113
  }
114
114
  res.locals['savedFiles'] = savedFiles;
115
115
  return next();
@@ -144,7 +144,7 @@ router.post('/', asyncHandler(multipartHandler), asyncHandler(async (req, res, n
144
144
  }
145
145
  }
146
146
  catch (error) {
147
- if (error instanceof ForbiddenException) {
147
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
148
148
  return next();
149
149
  }
150
150
  throw error;
@@ -158,7 +158,7 @@ const importSchema = Joi.object({
158
158
  router.post('/import', asyncHandler(async (req, res, next) => {
159
159
  const { error } = importSchema.validate(req.body);
160
160
  if (error) {
161
- throw new InvalidPayloadException(error.message);
161
+ throw new InvalidPayloadError({ reason: error.message });
162
162
  }
163
163
  const service = new FilesService({
164
164
  accountability: req.accountability,
@@ -170,7 +170,7 @@ router.post('/import', asyncHandler(async (req, res, next) => {
170
170
  res.locals['payload'] = { data: record || null };
171
171
  }
172
172
  catch (error) {
173
- if (error instanceof ForbiddenException) {
173
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
174
174
  return next();
175
175
  }
176
176
  throw error;
@@ -232,7 +232,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
232
232
  res.locals['payload'] = { data: result || null };
233
233
  }
234
234
  catch (error) {
235
- if (error instanceof ForbiddenException) {
235
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
236
236
  return next();
237
237
  }
238
238
  throw error;
@@ -250,7 +250,7 @@ router.patch('/:pk', asyncHandler(multipartHandler), asyncHandler(async (req, re
250
250
  res.locals['payload'] = { data: record || null };
251
251
  }
252
252
  catch (error) {
253
- if (error instanceof ForbiddenException) {
253
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
254
254
  return next();
255
255
  }
256
256
  throw error;
@@ -1,6 +1,7 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
3
  import { UUID_REGEX } from '../constants.js';
3
- import { ForbiddenException } from '../exceptions/index.js';
4
+ import { ErrorCode } from '../errors/index.js';
4
5
  import { getFlowManager } from '../flows.js';
5
6
  import { respond } from '../middleware/respond.js';
6
7
  import useCollection from '../middleware/use-collection.js';
@@ -56,7 +57,7 @@ router.post('/', asyncHandler(async (req, res, next) => {
56
57
  }
57
58
  }
58
59
  catch (error) {
59
- if (error instanceof ForbiddenException) {
60
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
60
61
  return next();
61
62
  }
62
63
  throw error;
@@ -109,7 +110,7 @@ router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) =
109
110
  res.locals['payload'] = { data: result };
110
111
  }
111
112
  catch (error) {
112
- if (error instanceof ForbiddenException) {
113
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
113
114
  return next();
114
115
  }
115
116
  throw error;
@@ -127,7 +128,7 @@ router.patch('/:pk', asyncHandler(async (req, res, next) => {
127
128
  res.locals['payload'] = { data: item || null };
128
129
  }
129
130
  catch (error) {
130
- if (error instanceof ForbiddenException) {
131
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
131
132
  return next();
132
133
  }
133
134
  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 || 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,5 +1,6 @@
1
+ import { isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { ForbiddenException, RouteNotFoundException } from '../exceptions/index.js';
3
+ import { ErrorCode, ForbiddenError, RouteNotFoundError } from '../errors/index.js';
3
4
  import collectionExists from '../middleware/collection-exists.js';
4
5
  import { respond } from '../middleware/respond.js';
5
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -10,9 +11,9 @@ import { sanitizeQuery } from '../utils/sanitize-query.js';
10
11
  const router = express.Router();
11
12
  router.post('/:collection', collectionExists, asyncHandler(async (req, res, next) => {
12
13
  if (req.params['collection'].startsWith('directus_'))
13
- throw new ForbiddenException();
14
+ throw new ForbiddenError();
14
15
  if (req.singleton) {
15
- throw new RouteNotFoundException(req.path);
16
+ throw new RouteNotFoundError({ path: req.path });
16
17
  }
17
18
  const service = new ItemsService(req.collection, {
18
19
  accountability: req.accountability,
@@ -38,7 +39,7 @@ router.post('/:collection', collectionExists, 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;
@@ -47,7 +48,7 @@ router.post('/:collection', collectionExists, asyncHandler(async (req, res, next
47
48
  }), respond);
48
49
  const readHandler = asyncHandler(async (req, res, next) => {
49
50
  if (req.params['collection'].startsWith('directus_'))
50
- throw new ForbiddenException();
51
+ throw new ForbiddenError();
51
52
  const service = new ItemsService(req.collection, {
52
53
  accountability: req.accountability,
53
54
  schema: req.schema,
@@ -77,7 +78,7 @@ router.search('/:collection', collectionExists, validateBatch('read'), readHandl
77
78
  router.get('/:collection', collectionExists, readHandler, respond);
78
79
  router.get('/:collection/:pk', collectionExists, asyncHandler(async (req, res, next) => {
79
80
  if (req.params['collection'].startsWith('directus_'))
80
- throw new ForbiddenException();
81
+ throw new ForbiddenError();
81
82
  const service = new ItemsService(req.collection, {
82
83
  accountability: req.accountability,
83
84
  schema: req.schema,
@@ -90,7 +91,7 @@ router.get('/:collection/:pk', collectionExists, asyncHandler(async (req, res, n
90
91
  }), respond);
91
92
  router.patch('/:collection', collectionExists, validateBatch('update'), asyncHandler(async (req, res, next) => {
92
93
  if (req.params['collection'].startsWith('directus_'))
93
- throw new ForbiddenException();
94
+ throw new ForbiddenError();
94
95
  const service = new ItemsService(req.collection, {
95
96
  accountability: req.accountability,
96
97
  schema: req.schema,
@@ -117,7 +118,7 @@ router.patch('/:collection', collectionExists, validateBatch('update'), asyncHan
117
118
  res.locals['payload'] = { data: result };
118
119
  }
119
120
  catch (error) {
120
- if (error instanceof ForbiddenException) {
121
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
121
122
  return next();
122
123
  }
123
124
  throw error;
@@ -126,9 +127,9 @@ router.patch('/:collection', collectionExists, validateBatch('update'), asyncHan
126
127
  }), respond);
127
128
  router.patch('/:collection/:pk', collectionExists, asyncHandler(async (req, res, next) => {
128
129
  if (req.params['collection'].startsWith('directus_'))
129
- throw new ForbiddenException();
130
+ throw new ForbiddenError();
130
131
  if (req.singleton) {
131
- throw new RouteNotFoundException(req.path);
132
+ throw new RouteNotFoundError({ path: req.path });
132
133
  }
133
134
  const service = new ItemsService(req.collection, {
134
135
  accountability: req.accountability,
@@ -140,7 +141,7 @@ router.patch('/:collection/:pk', collectionExists, asyncHandler(async (req, res,
140
141
  res.locals['payload'] = { data: result || null };
141
142
  }
142
143
  catch (error) {
143
- if (error instanceof ForbiddenException) {
144
+ if (isDirectusError(error, ErrorCode.Forbidden)) {
144
145
  return next();
145
146
  }
146
147
  throw error;
@@ -149,7 +150,7 @@ router.patch('/:collection/:pk', collectionExists, asyncHandler(async (req, res,
149
150
  }), respond);
150
151
  router.delete('/:collection', collectionExists, validateBatch('delete'), asyncHandler(async (req, _res, next) => {
151
152
  if (req.params['collection'].startsWith('directus_'))
152
- throw new ForbiddenException();
153
+ throw new ForbiddenError();
153
154
  const service = new ItemsService(req.collection, {
154
155
  accountability: req.accountability,
155
156
  schema: req.schema,
@@ -168,7 +169,7 @@ router.delete('/:collection', collectionExists, validateBatch('delete'), asyncHa
168
169
  }), respond);
169
170
  router.delete('/:collection/:pk', collectionExists, asyncHandler(async (req, _res, next) => {
170
171
  if (req.params['collection'].startsWith('directus_'))
171
- throw new ForbiddenException();
172
+ throw new ForbiddenError();
172
173
  const service = new ItemsService(req.collection, {
173
174
  accountability: req.accountability,
174
175
  schema: req.schema,
@@ -1,6 +1,6 @@
1
1
  import getDatabase from '../database/index.js';
2
2
  import emitter from '../emitter.js';
3
- import { RouteNotFoundException } from '../exceptions/index.js';
3
+ import { RouteNotFoundError } from '../errors/index.js';
4
4
  /**
5
5
  * Handles not found routes.
6
6
  *
@@ -22,7 +22,7 @@ const notFound = async (req, res, next) => {
22
22
  if (hooksResult) {
23
23
  return next();
24
24
  }
25
- next(new RouteNotFoundException(req.path));
25
+ next(new RouteNotFoundError({ path: req.path }));
26
26
  }
27
27
  catch (err) {
28
28
  next(err);