@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
@@ -5,13 +5,13 @@ import WebSocket, { WebSocketServer } from 'ws';
5
5
  import { fromZodError } from 'zod-validation-error';
6
6
  import emitter from '../../emitter.js';
7
7
  import env from '../../env.js';
8
- import { InvalidConfigException, TokenExpiredException } from '../../exceptions/index.js';
8
+ import { InvalidProviderConfigError, TokenExpiredError } from '../../errors/index.js';
9
9
  import logger from '../../logger.js';
10
10
  import { createRateLimiter } from '../../rate-limiter.js';
11
11
  import { getAccountabilityForToken } from '../../utils/get-accountability-for-token.js';
12
12
  import { toBoolean } from '../../utils/to-boolean.js';
13
13
  import { authenticateConnection, authenticationSuccess } from '../authenticate.js';
14
- import { WebSocketException, handleWebSocketException } from '../exceptions.js';
14
+ import { WebSocketError, handleWebSocketError } from '../errors.js';
15
15
  import { AuthMode, WebSocketAuthMessage, WebSocketMessage } from '../messages.js';
16
16
  import { getExpiresAtForToken } from '../utils/get-expires-at-for-token.js';
17
17
  import { getMessageType } from '../utils/message.js';
@@ -45,7 +45,10 @@ export default class SocketController {
45
45
  const authTimeout = Number(env[`${configPrefix}_AUTH_TIMEOUT`]) * 1000;
46
46
  const maxConnections = `${configPrefix}_CONN_LIMIT` in env ? Number(env[`${configPrefix}_CONN_LIMIT`]) : Number.POSITIVE_INFINITY;
47
47
  if (!authMode.success) {
48
- throw new InvalidConfigException(fromZodError(authMode.error, { prefix: `${configPrefix}_AUTH` }).message);
48
+ throw new InvalidProviderConfigError({
49
+ provider: 'ws',
50
+ reason: fromZodError(authMode.error, { prefix: `${configPrefix}_AUTH` }).message,
51
+ });
49
52
  }
50
53
  return {
51
54
  endpoint,
@@ -122,8 +125,8 @@ export default class SocketController {
122
125
  }
123
126
  catch {
124
127
  logger.debug('WebSocket authentication handshake failed');
125
- const error = new WebSocketException('auth', 'AUTH_FAILED', 'Authentication handshake failed.');
126
- handleWebSocketException(ws, error, 'auth');
128
+ const error = new WebSocketError('auth', 'AUTH_FAILED', 'Authentication handshake failed.');
129
+ handleWebSocketError(ws, error, 'auth');
127
130
  ws.close();
128
131
  }
129
132
  });
@@ -141,8 +144,8 @@ export default class SocketController {
141
144
  }
142
145
  catch (limit) {
143
146
  const timeout = limit?.msBeforeNext ?? this.rateLimiter.msDuration;
144
- const error = new WebSocketException('server', 'REQUESTS_EXCEEDED', `Too many messages, retry after ${timeout}ms.`);
145
- handleWebSocketException(client, error, 'server');
147
+ const error = new WebSocketError('server', 'REQUESTS_EXCEEDED', `Too many messages, retry after ${timeout}ms.`);
148
+ handleWebSocketError(client, error, 'server');
146
149
  logger.debug(`WebSocket#${client.uid} is rate limited`);
147
150
  return;
148
151
  }
@@ -152,7 +155,7 @@ export default class SocketController {
152
155
  message = this.parseMessage(data.toString());
153
156
  }
154
157
  catch (err) {
155
- handleWebSocketException(client, err, 'server');
158
+ handleWebSocketError(client, err, 'server');
156
159
  return;
157
160
  }
158
161
  if (getMessageType(message) === 'auth') {
@@ -198,7 +201,7 @@ export default class SocketController {
198
201
  message = WebSocketMessage.parse(parseJSON(data));
199
202
  }
200
203
  catch (err) {
201
- throw new WebSocketException('server', 'INVALID_PAYLOAD', 'Unable to parse the incoming message.');
204
+ throw new WebSocketError('server', 'INVALID_PAYLOAD', 'Unable to parse the incoming message.');
202
205
  }
203
206
  return message;
204
207
  }
@@ -217,10 +220,10 @@ export default class SocketController {
217
220
  emitter.emitAction('websocket.auth.failure', { client });
218
221
  client.accountability = null;
219
222
  client.expires_at = null;
220
- const _error = error instanceof WebSocketException
223
+ const _error = error instanceof WebSocketError
221
224
  ? error
222
- : new WebSocketException('auth', 'AUTH_FAILED', 'Authentication failed.', message.uid);
223
- handleWebSocketException(client, _error, 'auth');
225
+ : new WebSocketError('auth', 'AUTH_FAILED', 'Authentication failed.', message.uid);
226
+ handleWebSocketError(client, _error, 'auth');
224
227
  if (this.authentication.mode !== 'public') {
225
228
  client.close();
226
229
  }
@@ -240,10 +243,10 @@ export default class SocketController {
240
243
  client.auth_timer = setTimeout(() => {
241
244
  client.accountability = null;
242
245
  client.expires_at = null;
243
- handleWebSocketException(client, new TokenExpiredException(), 'auth');
246
+ handleWebSocketError(client, new TokenExpiredError(), 'auth');
244
247
  waitForMessageType(client, 'auth', this.authentication.timeout).catch((msg) => {
245
- const error = new WebSocketException('auth', 'AUTH_TIMEOUT', 'Authentication timed out.', msg?.uid);
246
- handleWebSocketException(client, error, 'auth');
248
+ const error = new WebSocketError('auth', 'AUTH_TIMEOUT', 'Authentication timed out.', msg?.uid);
249
+ handleWebSocketError(client, error, 'auth');
247
250
  if (this.authentication.mode !== 'public') {
248
251
  client.close();
249
252
  }
@@ -5,7 +5,7 @@ import { bindPubSub } from '../../services/graphql/subscription.js';
5
5
  import { GraphQLService } from '../../services/index.js';
6
6
  import { getSchema } from '../../utils/get-schema.js';
7
7
  import { authenticateConnection, refreshAccountability } from '../authenticate.js';
8
- import { handleWebSocketException } from '../exceptions.js';
8
+ import { handleWebSocketError } from '../errors.js';
9
9
  import { ConnectionParams, WebSocketMessage } from '../messages.js';
10
10
  import { getMessageType } from '../utils/message.js';
11
11
  import SocketController from './base.js';
@@ -68,7 +68,7 @@ export class GraphQLSubscriptionController extends SocketController {
68
68
  await cb(JSON.stringify(message));
69
69
  }
70
70
  catch (error) {
71
- handleWebSocketException(client, error, MessageType.Error);
71
+ handleWebSocketError(client, error, MessageType.Error);
72
72
  }
73
73
  });
74
74
  },
@@ -1,5 +1,5 @@
1
1
  import env from '../../env.js';
2
- import { ServiceUnavailableException } from '../../index.js';
2
+ import { ServiceUnavailableError } from '../../errors/index.js';
3
3
  import { toBoolean } from '../../utils/to-boolean.js';
4
4
  import { GraphQLSubscriptionController } from './graphql.js';
5
5
  import { WebSocketController } from './rest.js';
@@ -12,14 +12,10 @@ export function createWebSocketController(server) {
12
12
  }
13
13
  export function getWebSocketController() {
14
14
  if (!toBoolean(env['WEBSOCKETS_ENABLED']) || !toBoolean(env['WEBSOCKETS_REST_ENABLED'])) {
15
- throw new ServiceUnavailableException('WebSocket server is disabled', {
16
- service: 'get-websocket-controller',
17
- });
15
+ throw new ServiceUnavailableError({ service: 'ws', reason: 'WebSocket server is disabled' });
18
16
  }
19
17
  if (!websocketController) {
20
- throw new ServiceUnavailableException('WebSocket server is not initialized', {
21
- service: 'get-websocket-controller',
22
- });
18
+ throw new ServiceUnavailableError({ service: 'ws', reason: 'WebSocket server is not initialized' });
23
19
  }
24
20
  return websocketController;
25
21
  }
@@ -3,7 +3,7 @@ import emitter from '../../emitter.js';
3
3
  import env from '../../env.js';
4
4
  import logger from '../../logger.js';
5
5
  import { refreshAccountability } from '../authenticate.js';
6
- import { WebSocketException, handleWebSocketException } from '../exceptions.js';
6
+ import { WebSocketError, handleWebSocketError } from '../errors.js';
7
7
  import { WebSocketMessage } from '../messages.js';
8
8
  import SocketController from './base.js';
9
9
  export class WebSocketController extends SocketController {
@@ -22,7 +22,7 @@ export class WebSocketController extends SocketController {
22
22
  emitter.emitAction('websocket.message', { message, client });
23
23
  }
24
24
  catch (error) {
25
- handleWebSocketException(client, error, 'server');
25
+ handleWebSocketError(client, error, 'server');
26
26
  return;
27
27
  }
28
28
  });
@@ -40,7 +40,7 @@ export class WebSocketController extends SocketController {
40
40
  message = parseJSON(data);
41
41
  }
42
42
  catch (err) {
43
- throw new WebSocketException('server', 'INVALID_PAYLOAD', 'Unable to parse the incoming message.');
43
+ throw new WebSocketError('server', 'INVALID_PAYLOAD', 'Unable to parse the incoming message.');
44
44
  }
45
45
  return message;
46
46
  }
@@ -1,16 +1,16 @@
1
- import { BaseException } from '@directus/exceptions';
1
+ import type { DirectusError } from '@directus/errors';
2
2
  import type { WebSocket } from 'ws';
3
3
  import { ZodError } from 'zod';
4
4
  import type { WebSocketResponse } from './messages.js';
5
5
  import type { WebSocketClient } from './types.js';
6
- export declare class WebSocketException extends Error {
6
+ export declare class WebSocketError extends Error {
7
7
  type: string;
8
8
  code: string;
9
9
  uid: string | number | undefined;
10
10
  constructor(type: string, code: string, message: string, uid?: string | number);
11
11
  toJSON(): WebSocketResponse;
12
12
  toMessage(): string;
13
- static fromException(error: BaseException, type?: string): WebSocketException;
14
- static fromZodError(error: ZodError, type?: string): WebSocketException;
13
+ static fromError(error: DirectusError<unknown>, type?: string): WebSocketError;
14
+ static fromZodError(error: ZodError, type?: string): WebSocketError;
15
15
  }
16
- export declare function handleWebSocketException(client: WebSocketClient | WebSocket, error: unknown, type?: string): void;
16
+ export declare function handleWebSocketError(client: WebSocketClient | WebSocket, error: unknown, type?: string): void;
@@ -1,8 +1,8 @@
1
- import { BaseException } from '@directus/exceptions';
1
+ import { isDirectusError } from '@directus/errors';
2
2
  import { ZodError } from 'zod';
3
3
  import { fromZodError } from 'zod-validation-error';
4
4
  import logger from '../logger.js';
5
- export class WebSocketException extends Error {
5
+ export class WebSocketError extends Error {
6
6
  type;
7
7
  code;
8
8
  uid;
@@ -29,25 +29,25 @@ export class WebSocketException extends Error {
29
29
  toMessage() {
30
30
  return JSON.stringify(this.toJSON());
31
31
  }
32
- static fromException(error, type = 'unknown') {
33
- return new WebSocketException(type, error.code, error.message);
32
+ static fromError(error, type = 'unknown') {
33
+ return new WebSocketError(type, error.code, error.message);
34
34
  }
35
35
  static fromZodError(error, type = 'unknown') {
36
36
  const zError = fromZodError(error);
37
- return new WebSocketException(type, 'INVALID_PAYLOAD', zError.message);
37
+ return new WebSocketError(type, 'INVALID_PAYLOAD', zError.message);
38
38
  }
39
39
  }
40
- export function handleWebSocketException(client, error, type) {
41
- if (error instanceof BaseException) {
42
- client.send(WebSocketException.fromException(error, type).toMessage());
40
+ export function handleWebSocketError(client, error, type) {
41
+ if (isDirectusError(error)) {
42
+ client.send(WebSocketError.fromError(error, type).toMessage());
43
43
  return;
44
44
  }
45
- if (error instanceof WebSocketException) {
45
+ if (error instanceof WebSocketError) {
46
46
  client.send(error.toMessage());
47
47
  return;
48
48
  }
49
49
  if (error instanceof ZodError) {
50
- client.send(WebSocketException.fromZodError(error, type).toMessage());
50
+ client.send(WebSocketError.fromZodError(error, type).toMessage());
51
51
  return;
52
52
  }
53
53
  // unhandled exceptions
@@ -2,7 +2,7 @@ import emitter from '../../emitter.js';
2
2
  import { ItemsService, MetaService } from '../../services/index.js';
3
3
  import { getSchema } from '../../utils/get-schema.js';
4
4
  import { sanitizeQuery } from '../../utils/sanitize-query.js';
5
- import { WebSocketException, handleWebSocketException } from '../exceptions.js';
5
+ import { WebSocketError, handleWebSocketError } from '../errors.js';
6
6
  import { WebSocketItemsMessage } from '../messages.js';
7
7
  import { fmtMessage, getMessageType } from '../utils/message.js';
8
8
  export class ItemsHandler {
@@ -14,11 +14,11 @@ export class ItemsHandler {
14
14
  const parsedMessage = WebSocketItemsMessage.parse(message);
15
15
  this.onMessage(client, parsedMessage).catch((err) => {
16
16
  // this catch is required because the async onMessage function is not awaited
17
- handleWebSocketException(client, err, 'items');
17
+ handleWebSocketError(client, err, 'items');
18
18
  });
19
19
  }
20
20
  catch (err) {
21
- handleWebSocketException(client, err, 'items');
21
+ handleWebSocketError(client, err, 'items');
22
22
  }
23
23
  });
24
24
  }
@@ -27,7 +27,7 @@ export class ItemsHandler {
27
27
  const accountability = client.accountability;
28
28
  const schema = await getSchema();
29
29
  if (!schema.collections[message.collection] || message.collection.startsWith('directus_')) {
30
- throw new WebSocketException('items', 'INVALID_COLLECTION', 'The provided collection does not exists or is not accessible.', uid);
30
+ throw new WebSocketError('items', 'INVALID_COLLECTION', 'The provided collection does not exists or is not accessible.', uid);
31
31
  }
32
32
  const isSingleton = !!schema.collections[message.collection]?.singleton;
33
33
  const service = new ItemsService(message.collection, { schema, accountability });
@@ -95,7 +95,7 @@ export class ItemsHandler {
95
95
  result = await service.deleteByQuery(query);
96
96
  }
97
97
  else {
98
- throw new WebSocketException('items', 'INVALID_PAYLOAD', "Either 'ids', 'id' or 'query' is required for a DELETE request.", uid);
98
+ throw new WebSocketError('items', 'INVALID_PAYLOAD', "Either 'ids', 'id' or 'query' is required for a DELETE request.", uid);
99
99
  }
100
100
  }
101
101
  client.send(fmtMessage('items', { data: result, ...(meta ? { meta } : {}) }, uid));
@@ -1,12 +1,12 @@
1
1
  import emitter from '../../emitter.js';
2
- import { InvalidPayloadException } from '../../index.js';
2
+ import { InvalidPayloadError } from '../../errors/index.js';
3
3
  import { getMessenger } from '../../messenger.js';
4
4
  import { CollectionsService, FieldsService, MetaService } from '../../services/index.js';
5
5
  import { getSchema } from '../../utils/get-schema.js';
6
6
  import { getService } from '../../utils/get-service.js';
7
7
  import { sanitizeQuery } from '../../utils/sanitize-query.js';
8
8
  import { refreshAccountability } from '../authenticate.js';
9
- import { WebSocketException, handleWebSocketException } from '../exceptions.js';
9
+ import { WebSocketError, handleWebSocketError } from '../errors.js';
10
10
  import { WebSocketSubscribeMessage } from '../messages.js';
11
11
  import { fmtMessage, getMessageType } from '../utils/message.js';
12
12
  /**
@@ -46,7 +46,7 @@ export class SubscribeHandler {
46
46
  this.onMessage(client, WebSocketSubscribeMessage.parse(message));
47
47
  }
48
48
  catch (error) {
49
- handleWebSocketException(client, error, 'subscribe');
49
+ handleWebSocketError(client, error, 'subscribe');
50
50
  }
51
51
  });
52
52
  // unsubscribe when a connection drops
@@ -60,7 +60,7 @@ export class SubscribeHandler {
60
60
  subscribe(subscription) {
61
61
  const { collection } = subscription;
62
62
  if ('item' in subscription && ['directus_fields', 'directus_relations'].includes(collection)) {
63
- throw new InvalidPayloadException(`Cannot subscribe to a specific item in the ${collection} collection.`);
63
+ throw new InvalidPayloadError({ reason: `Cannot subscribe to a specific item in the ${collection} collection.` });
64
64
  }
65
65
  if (!this.subscriptions[collection]) {
66
66
  this.subscriptions[collection] = new Set();
@@ -115,7 +115,7 @@ export class SubscribeHandler {
115
115
  client.send(fmtMessage('subscription', result, subscription.uid));
116
116
  }
117
117
  catch (err) {
118
- handleWebSocketException(client, err, 'subscribe');
118
+ handleWebSocketError(client, err, 'subscribe');
119
119
  }
120
120
  }
121
121
  }
@@ -129,7 +129,7 @@ export class SubscribeHandler {
129
129
  const accountability = client.accountability;
130
130
  const schema = await getSchema();
131
131
  if (!accountability?.admin && !schema.collections[collection]) {
132
- throw new WebSocketException('subscribe', 'INVALID_COLLECTION', 'The provided collection does not exists or is not accessible.', message.uid);
132
+ throw new WebSocketError('subscribe', 'INVALID_COLLECTION', 'The provided collection does not exists or is not accessible.', message.uid);
133
133
  }
134
134
  const subscription = {
135
135
  client,
@@ -164,7 +164,7 @@ export class SubscribeHandler {
164
164
  client.send(fmtMessage('subscription', data, subscription.uid));
165
165
  }
166
166
  catch (err) {
167
- handleWebSocketException(client, err, 'subscribe');
167
+ handleWebSocketError(client, err, 'subscribe');
168
168
  }
169
169
  }
170
170
  if (getMessageType(message) === 'unsubscribe') {
@@ -173,7 +173,7 @@ export class SubscribeHandler {
173
173
  client.send(fmtMessage('subscription', { event: 'unsubscribe' }, message.uid));
174
174
  }
175
175
  catch (err) {
176
- handleWebSocketException(client, err, 'unsubscribe');
176
+ handleWebSocketError(client, err, 'unsubscribe');
177
177
  }
178
178
  }
179
179
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/api",
3
- "version": "11.1.0",
3
+ "version": "12.0.0",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "keywords": [
6
6
  "directus",
@@ -143,20 +143,21 @@
143
143
  "ws": "8.12.1",
144
144
  "zod": "3.21.4",
145
145
  "zod-validation-error": "1.0.1",
146
- "@directus/app": "10.3.1",
146
+ "@directus/app": "10.4.0",
147
147
  "@directus/constants": "10.2.1",
148
- "@directus/exceptions": "10.0.3",
149
- "@directus/extensions-sdk": "10.1.4",
150
- "@directus/pressure": "1.0.4",
148
+ "@directus/errors": "0.0.1",
149
+ "@directus/extensions-sdk": "10.1.5",
150
+ "@directus/pressure": "1.0.5",
151
151
  "@directus/schema": "10.0.1",
152
152
  "@directus/specs": "10.1.1",
153
- "@directus/storage": "10.0.3",
154
- "@directus/storage-driver-azure": "10.0.5",
155
- "@directus/storage-driver-cloudinary": "10.0.5",
156
- "@directus/storage-driver-gcs": "10.0.5",
157
- "@directus/storage-driver-local": "10.0.5",
158
- "@directus/storage-driver-s3": "10.0.5",
159
- "@directus/utils": "10.0.5"
153
+ "@directus/storage": "10.0.4",
154
+ "@directus/storage-driver-azure": "10.0.6",
155
+ "@directus/storage-driver-cloudinary": "10.0.6",
156
+ "@directus/storage-driver-gcs": "10.0.6",
157
+ "@directus/storage-driver-local": "10.0.6",
158
+ "@directus/storage-driver-s3": "10.0.6",
159
+ "@directus/utils": "10.0.6",
160
+ "@directus/validation": "0.0.1"
160
161
  },
161
162
  "devDependencies": {
162
163
  "@ngneat/falso": "6.4.0",
@@ -203,13 +204,12 @@
203
204
  "supertest": "6.3.3",
204
205
  "typescript": "5.0.4",
205
206
  "vitest": "0.31.1",
207
+ "@directus/random": "0.2.1",
206
208
  "@directus/tsconfig": "0.0.7",
207
- "@directus/types": "10.1.1"
209
+ "@directus/types": "10.1.2"
208
210
  },
209
211
  "optionalDependencies": {
210
212
  "@keyv/redis": "2.5.8",
211
- "keyv-memcache": "1.3.3",
212
- "memcached": "2.2.2",
213
213
  "mysql": "2.18.1",
214
214
  "nodemailer-mailgun-transport": "2.1.5",
215
215
  "nodemailer-sendgrid": "1.0.3",
@@ -1,4 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export declare class ContentTooLargeException extends BaseException {
3
- constructor(message: string);
4
- }
@@ -1,6 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class ContentTooLargeException extends BaseException {
3
- constructor(message) {
4
- super(message, 413, 'CONTENT_TOO_LARGE');
5
- }
6
- }
@@ -1,9 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- type Exceptions = {
3
- collection: string;
4
- field: string;
5
- };
6
- export declare class ContainsNullValuesException extends BaseException {
7
- constructor(field: string, exceptions?: Exceptions);
8
- }
9
- export {};
@@ -1,6 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class ContainsNullValuesException extends BaseException {
3
- constructor(field, exceptions) {
4
- super(`Field "${field}" contains null values.`, 400, 'CONTAINS_NULL_VALUES', exceptions);
5
- }
6
- }
@@ -1,10 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- type Extensions = {
3
- collection: string;
4
- field: string;
5
- invalid?: string;
6
- };
7
- export declare class InvalidForeignKeyException extends BaseException {
8
- constructor(field: string | null, extensions?: Extensions);
9
- }
10
- export {};
@@ -1,11 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class InvalidForeignKeyException extends BaseException {
3
- constructor(field, extensions) {
4
- if (field) {
5
- super(`Invalid foreign key in field "${field}".`, 400, 'INVALID_FOREIGN_KEY', extensions);
6
- }
7
- else {
8
- super(`Invalid foreign key.`, 400, 'INVALID_FOREIGN_KEY', extensions);
9
- }
10
- }
11
- }
@@ -1,9 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- type Exceptions = {
3
- collection: string;
4
- field: string;
5
- };
6
- export declare class NotNullViolationException extends BaseException {
7
- constructor(field: string, exceptions?: Exceptions);
8
- }
9
- export {};
@@ -1,6 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class NotNullViolationException extends BaseException {
3
- constructor(field, exceptions) {
4
- super(`Value for field "${field}" can't be null.`, 400, 'NOT_NULL_VIOLATION', exceptions);
5
- }
6
- }
@@ -1,10 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- type Extensions = {
3
- collection: string;
4
- field: string | null;
5
- invalid?: string | undefined;
6
- };
7
- export declare class RecordNotUniqueException extends BaseException {
8
- constructor(field: string | null, extensions?: Extensions);
9
- }
10
- export {};
@@ -1,11 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class RecordNotUniqueException extends BaseException {
3
- constructor(field, extensions) {
4
- if (field) {
5
- super(`Field "${field}" has to be unique.`, 400, 'RECORD_NOT_UNIQUE', extensions);
6
- }
7
- else {
8
- super(`Field has to be unique.`, 400, 'RECORD_NOT_UNIQUE', extensions);
9
- }
10
- }
11
- }
@@ -1,10 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- type Exceptions = {
3
- collection: string;
4
- field: string | null;
5
- invalid?: string;
6
- };
7
- export declare class ValueOutOfRangeException extends BaseException {
8
- constructor(field: string | null, exceptions?: Exceptions);
9
- }
10
- export {};
@@ -1,11 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class ValueOutOfRangeException extends BaseException {
3
- constructor(field, exceptions) {
4
- if (field) {
5
- super(`Numeric value in field "${field ?? ''}" is out of range.`, 400, 'VALUE_OUT_OF_RANGE', exceptions);
6
- }
7
- else {
8
- super(`Numeric value is out of range.`, 400, 'VALUE_OUT_OF_RANGE', exceptions);
9
- }
10
- }
11
- }
@@ -1,9 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- type Extensions = {
3
- collection: string;
4
- field: string | null;
5
- };
6
- export declare class ValueTooLongException extends BaseException {
7
- constructor(field: string | null, extensions?: Extensions);
8
- }
9
- export {};
@@ -1,11 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class ValueTooLongException extends BaseException {
3
- constructor(field, extensions) {
4
- if (field) {
5
- super(`Value for field "${field}" is too long.`, 400, 'VALUE_TOO_LONG', extensions);
6
- }
7
- else {
8
- super(`Value is too long.`, 400, 'VALUE_TOO_LONG', extensions);
9
- }
10
- }
11
- }
@@ -1,6 +0,0 @@
1
- import * as exceptions from '@directus/exceptions';
2
- declare const BaseException: typeof exceptions.BaseException;
3
- export declare class ForbiddenException extends BaseException {
4
- constructor();
5
- }
6
- export {};
@@ -1,13 +0,0 @@
1
- import * as exceptions from '@directus/exceptions';
2
- const { BaseException } = exceptions;
3
- export class ForbiddenException extends BaseException {
4
- constructor() {
5
- super(`You don't have permission to access this.`, 403, 'FORBIDDEN');
6
- /**
7
- * We currently don't show the reason for a forbidden exception in the API output, as that
8
- * has the potential to leak schema information (eg a "No permission" vs "No permission to files"
9
- * would leak that a thing called "files" exists.
10
- * Ref https://github.com/directus/directus/discussions/4368
11
- */
12
- }
13
- }
@@ -1,4 +0,0 @@
1
- import * as sharedExceptions from '@directus/exceptions';
2
- export declare class GraphQLValidationException extends sharedExceptions.BaseException {
3
- constructor(extensions: Record<string, any>);
4
- }
@@ -1,6 +0,0 @@
1
- import * as sharedExceptions from '@directus/exceptions';
2
- export class GraphQLValidationException extends sharedExceptions.BaseException {
3
- constructor(extensions) {
4
- super('GraphQL validation error.', 400, 'GRAPHQL_VALIDATION_EXCEPTION', extensions);
5
- }
6
- }
@@ -1,9 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- type Extensions = {
3
- limit: number;
4
- reset: Date;
5
- };
6
- export declare class HitRateLimitException extends BaseException {
7
- constructor(message: string, extensions: Extensions);
8
- }
9
- export {};
@@ -1,6 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class HitRateLimitException extends BaseException {
3
- constructor(message, extensions) {
4
- super(message, 429, 'REQUESTS_EXCEEDED', extensions);
5
- }
6
- }
@@ -1,4 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export declare class IllegalAssetTransformation extends BaseException {
3
- constructor(message: string);
4
- }
@@ -1,6 +0,0 @@
1
- import { BaseException } from '@directus/exceptions';
2
- export class IllegalAssetTransformation extends BaseException {
3
- constructor(message) {
4
- super(message, 400, 'ILLEGAL_ASSET_TRANSFORMATION');
5
- }
6
- }