@directus/api 18.2.1 → 19.0.1

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 (90) hide show
  1. package/dist/app.js +0 -3
  2. package/dist/auth/drivers/ldap.js +1 -1
  3. package/dist/auth/drivers/local.js +1 -1
  4. package/dist/auth/drivers/oauth2.js +1 -1
  5. package/dist/auth/drivers/openid.js +1 -1
  6. package/dist/cache.js +1 -1
  7. package/dist/cli/utils/create-env/env-stub.liquid +2 -2
  8. package/dist/controllers/activity.js +1 -1
  9. package/dist/controllers/assets.js +9 -12
  10. package/dist/controllers/auth.js +7 -6
  11. package/dist/controllers/collections.js +1 -2
  12. package/dist/controllers/dashboards.js +1 -2
  13. package/dist/controllers/extensions.js +30 -0
  14. package/dist/controllers/fields.js +1 -3
  15. package/dist/controllers/flows.js +1 -2
  16. package/dist/controllers/folders.js +1 -2
  17. package/dist/controllers/items.js +3 -4
  18. package/dist/controllers/notifications.js +1 -2
  19. package/dist/controllers/operations.js +1 -2
  20. package/dist/controllers/panels.js +1 -2
  21. package/dist/controllers/presets.js +1 -2
  22. package/dist/controllers/roles.js +1 -2
  23. package/dist/controllers/translations.js +1 -2
  24. package/dist/controllers/users.js +1 -2
  25. package/dist/controllers/webhooks.js +10 -74
  26. package/dist/database/migrations/20240122A-add-report-url-fields.d.ts +3 -0
  27. package/dist/database/migrations/20240122A-add-report-url-fields.js +14 -0
  28. package/dist/database/migrations/20240204A-marketplace.js +17 -5
  29. package/dist/database/migrations/20240305A-change-useragent-type.d.ts +3 -0
  30. package/dist/database/migrations/20240305A-change-useragent-type.js +19 -0
  31. package/dist/database/migrations/20240311A-deprecate-webhooks.d.ts +13 -0
  32. package/dist/database/migrations/20240311A-deprecate-webhooks.js +125 -0
  33. package/dist/database/run-ast.js +4 -3
  34. package/dist/extensions/manager.d.ts +1 -0
  35. package/dist/extensions/manager.js +4 -1
  36. package/dist/middleware/authenticate.js +1 -1
  37. package/dist/services/activity.d.ts +2 -1
  38. package/dist/services/authorization.d.ts +2 -2
  39. package/dist/services/collections.d.ts +1 -1
  40. package/dist/services/collections.js +8 -7
  41. package/dist/services/extensions.d.ts +3 -0
  42. package/dist/services/extensions.js +42 -10
  43. package/dist/services/fields.d.ts +2 -1
  44. package/dist/services/fields.js +37 -7
  45. package/dist/services/files.d.ts +2 -2
  46. package/dist/services/flows.d.ts +2 -2
  47. package/dist/services/graphql/index.d.ts +2 -2
  48. package/dist/services/graphql/index.js +5 -0
  49. package/dist/services/import-export.js +4 -3
  50. package/dist/services/items.d.ts +2 -2
  51. package/dist/services/items.js +9 -8
  52. package/dist/services/notifications.d.ts +2 -2
  53. package/dist/services/operations.d.ts +2 -2
  54. package/dist/services/payload.d.ts +2 -2
  55. package/dist/services/permissions/index.d.ts +2 -2
  56. package/dist/services/relations.js +10 -3
  57. package/dist/services/revisions.d.ts +2 -1
  58. package/dist/services/roles.d.ts +2 -2
  59. package/dist/services/roles.js +2 -1
  60. package/dist/services/shares.d.ts +2 -1
  61. package/dist/services/shares.js +1 -1
  62. package/dist/services/tfa.d.ts +2 -1
  63. package/dist/services/tfa.js +1 -1
  64. package/dist/services/users.d.ts +2 -2
  65. package/dist/services/users.js +3 -2
  66. package/dist/services/utils.d.ts +2 -2
  67. package/dist/services/utils.js +2 -2
  68. package/dist/services/versions.d.ts +1 -1
  69. package/dist/services/webhooks.d.ts +8 -4
  70. package/dist/services/webhooks.js +15 -12
  71. package/dist/types/items.d.ts +1 -8
  72. package/dist/types/services.d.ts +1 -2
  73. package/dist/utils/apply-diff.js +2 -1
  74. package/dist/utils/get-ast-from-query.js +1 -1
  75. package/dist/utils/get-auth-providers.d.ts +3 -1
  76. package/dist/utils/get-auth-providers.js +15 -4
  77. package/dist/utils/get-cache-headers.js +0 -3
  78. package/dist/utils/get-schema.d.ts +1 -1
  79. package/dist/utils/get-schema.js +52 -29
  80. package/dist/utils/merge-version-data.js +1 -1
  81. package/dist/utils/transaction.d.ts +9 -0
  82. package/dist/utils/transaction.js +15 -0
  83. package/dist/utils/validate-keys.d.ts +1 -2
  84. package/dist/websocket/controllers/base.d.ts +1 -3
  85. package/dist/websocket/controllers/base.js +12 -3
  86. package/dist/websocket/utils/items.d.ts +1 -1
  87. package/license +1 -1
  88. package/package.json +39 -37
  89. package/dist/webhooks.d.ts +0 -4
  90. package/dist/webhooks.js +0 -80
package/dist/app.js CHANGED
@@ -60,7 +60,6 @@ import { getConfigFromEnv } from './utils/get-config-from-env.js';
60
60
  import { Url } from './utils/url.js';
61
61
  import { validateEnv } from './utils/validate-env.js';
62
62
  import { validateStorage } from './utils/validate-storage.js';
63
- import { init as initWebhooks } from './webhooks.js';
64
63
  const require = createRequire(import.meta.url);
65
64
  export default async function createApp() {
66
65
  const env = useEnv();
@@ -240,8 +239,6 @@ export default async function createApp() {
240
239
  app.use(notFoundHandler);
241
240
  app.use(errorHandler);
242
241
  await emitter.emitInit('routes.after', { app });
243
- // Register all webhooks
244
- await initWebhooks();
245
242
  initTelemetry();
246
243
  await emitter.emitInit('app.after', { app });
247
244
  return app;
@@ -299,7 +299,7 @@ export function createLDAPAuthRouter(provider) {
299
299
  ip: getIPFromReq(req),
300
300
  role: null,
301
301
  };
302
- const userAgent = req.get('user-agent');
302
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
303
303
  if (userAgent)
304
304
  accountability.userAgent = userAgent;
305
305
  const origin = req.get('origin');
@@ -51,7 +51,7 @@ export function createLocalAuthRouter(provider) {
51
51
  ip: getIPFromReq(req),
52
52
  role: null,
53
53
  };
54
- const userAgent = req.get('user-agent');
54
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
55
55
  if (userAgent)
56
56
  accountability.userAgent = userAgent;
57
57
  const origin = req.get('origin');
@@ -254,7 +254,7 @@ export function createOAuth2AuthRouter(providerName) {
254
254
  ip: getIPFromReq(req),
255
255
  role: null,
256
256
  };
257
- const userAgent = req.get('user-agent');
257
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
258
258
  if (userAgent)
259
259
  accountability.userAgent = userAgent;
260
260
  const origin = req.get('origin');
@@ -275,7 +275,7 @@ export function createOpenIDAuthRouter(providerName) {
275
275
  ip: getIPFromReq(req),
276
276
  role: null,
277
277
  };
278
- const userAgent = req.get('user-agent');
278
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
279
279
  if (userAgent)
280
280
  accountability.userAgent = userAgent;
281
281
  const origin = req.get('origin');
package/dist/cache.js CHANGED
@@ -80,7 +80,7 @@ export async function getSystemCache(key) {
80
80
  }
81
81
  export async function setSchemaCache(schema) {
82
82
  const { localSchemaCache, sharedSchemaCache } = getCache();
83
- const schemaHash = await getSimpleHash(JSON.stringify(schema));
83
+ const schemaHash = getSimpleHash(JSON.stringify(schema));
84
84
  await sharedSchemaCache.set('hash', schemaHash);
85
85
  await localSchemaCache.set('schema', schema);
86
86
  await localSchemaCache.set('hash', schemaHash);
@@ -312,8 +312,8 @@ EXTENSIONS_AUTO_RELOAD=false
312
312
  ####################################################################################################
313
313
  ### Email
314
314
 
315
- # Email address from which emails are sent ["no-reply@directus.io"]
316
- EMAIL_FROM="no-reply@directus.io"
315
+ # Email address from which emails are sent ["no-reply@example.com"]
316
+ EMAIL_FROM="no-reply@example.com"
317
317
 
318
318
  # What to use to send emails. One of
319
319
  # sendmail, smtp, mailgun, sendgrid, ses.
@@ -70,7 +70,7 @@ router.post('/comment', asyncHandler(async (req, res, next) => {
70
70
  action: Action.COMMENT,
71
71
  user: req.accountability?.user,
72
72
  ip: getIPFromReq(req),
73
- user_agent: req.get('user-agent'),
73
+ user_agent: req.accountability?.userAgent,
74
74
  origin: req.get('origin'),
75
75
  });
76
76
  try {
@@ -180,17 +180,10 @@ asyncHandler(async (req, res) => {
180
180
  res.setHeader('Content-Length', stat.size);
181
181
  return res.end();
182
182
  }
183
- let isDataSent = false;
184
- stream.on('data', (chunk) => {
185
- isDataSent = true;
186
- res.write(chunk);
187
- });
188
- stream.on('end', () => {
189
- res.end();
190
- });
191
- stream.on('error', (e) => {
192
- logger.error(e, `Couldn't stream file ${file.id} to the client`);
193
- if (!isDataSent) {
183
+ stream
184
+ .on('error', (error) => {
185
+ logger.error(error, `Couldn't stream file ${file.id} to the client`);
186
+ if (!res.headersSent) {
194
187
  res.removeHeader('Content-Type');
195
188
  res.removeHeader('Content-Disposition');
196
189
  res.removeHeader('Cache-Control');
@@ -205,7 +198,11 @@ asyncHandler(async (req, res) => {
205
198
  ],
206
199
  });
207
200
  }
208
- });
201
+ else {
202
+ res.end();
203
+ }
204
+ })
205
+ .pipe(res);
209
206
  return undefined;
210
207
  }));
211
208
  export default router;
@@ -74,7 +74,7 @@ router.post('/refresh', asyncHandler(async (req, res, next) => {
74
74
  ip: getIPFromReq(req),
75
75
  role: null,
76
76
  };
77
- const userAgent = req.get('user-agent');
77
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
78
78
  if (userAgent)
79
79
  accountability.userAgent = userAgent;
80
80
  const origin = req.get('origin');
@@ -114,7 +114,7 @@ router.post('/logout', asyncHandler(async (req, res, next) => {
114
114
  ip: getIPFromReq(req),
115
115
  role: null,
116
116
  };
117
- const userAgent = req.get('user-agent');
117
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
118
118
  if (userAgent)
119
119
  accountability.userAgent = userAgent;
120
120
  const origin = req.get('origin');
@@ -148,7 +148,7 @@ router.post('/password/request', asyncHandler(async (req, _res, next) => {
148
148
  ip: getIPFromReq(req),
149
149
  role: null,
150
150
  };
151
- const userAgent = req.get('user-agent');
151
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
152
152
  if (userAgent)
153
153
  accountability.userAgent = userAgent;
154
154
  const origin = req.get('origin');
@@ -180,7 +180,7 @@ router.post('/password/reset', asyncHandler(async (req, _res, next) => {
180
180
  ip: getIPFromReq(req),
181
181
  role: null,
182
182
  };
183
- const userAgent = req.get('user-agent');
183
+ const userAgent = req.get('user-agent')?.substring(0, 1024);
184
184
  if (userAgent)
185
185
  accountability.userAgent = userAgent;
186
186
  const origin = req.get('origin');
@@ -190,9 +190,10 @@ router.post('/password/reset', asyncHandler(async (req, _res, next) => {
190
190
  await service.resetPassword(req.body.token, req.body.password);
191
191
  return next();
192
192
  }), respond);
193
- router.get('/', asyncHandler(async (_req, res, next) => {
193
+ router.get('/', asyncHandler(async (req, res, next) => {
194
+ const sessionOnly = 'sessionOnly' in req.query && (req.query['sessionOnly'] === '' || Boolean(req.query['sessionOnly']));
194
195
  res.locals['payload'] = {
195
- data: getAuthProviders(),
196
+ data: getAuthProviders({ sessionOnly }),
196
197
  disableDefault: env['AUTH_DISABLE_DEFAULT'],
197
198
  };
198
199
  return next();
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import { Router } from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import { validateBatch } from '../middleware/validate-batch.js';
6
5
  import { CollectionsService } from '../services/collections.js';
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -101,6 +101,36 @@ router.post('/registry/install', asyncHandler(async (req, _res, next) => {
101
101
  await service.install(extension, version);
102
102
  return next();
103
103
  }), respond);
104
+ router.post('/registry/reinstall', asyncHandler(async (req, _res, next) => {
105
+ if (req.accountability && req.accountability.admin !== true) {
106
+ throw new ForbiddenError();
107
+ }
108
+ const { extension } = req.body;
109
+ if (!extension) {
110
+ throw new ForbiddenError();
111
+ }
112
+ const service = new ExtensionsService({
113
+ accountability: req.accountability,
114
+ schema: req.schema,
115
+ });
116
+ await service.reinstall(extension);
117
+ return next();
118
+ }), respond);
119
+ router.delete(`/registry/uninstall/:pk(${UUID_REGEX})`, asyncHandler(async (req, _res, next) => {
120
+ if (req.accountability && req.accountability.admin !== true) {
121
+ throw new ForbiddenError();
122
+ }
123
+ const pk = req.params['pk'];
124
+ if (typeof pk !== 'string') {
125
+ throw new ForbiddenError();
126
+ }
127
+ const service = new ExtensionsService({
128
+ accountability: req.accountability,
129
+ schema: req.schema,
130
+ });
131
+ await service.uninstall(pk);
132
+ return next();
133
+ }), respond);
104
134
  router.patch(`/:pk(${UUID_REGEX})`, asyncHandler(async (req, res, next) => {
105
135
  if (req.accountability && req.accountability.admin !== true) {
106
136
  throw new ForbiddenError();
@@ -85,9 +85,7 @@ router.patch('/:collection', validateCollection, asyncHandler(async (req, res, n
85
85
  if (Array.isArray(req.body) === false) {
86
86
  throw new InvalidPayloadError({ reason: 'Submitted body has to be an array' });
87
87
  }
88
- for (const field of req.body) {
89
- await service.updateField(req.params['collection'], field);
90
- }
88
+ await service.updateFields(req.params['collection'], req.body);
91
89
  try {
92
90
  const results = [];
93
91
  for (const field of req.body) {
@@ -1,7 +1,6 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
3
  import { UUID_REGEX } from '../constants.js';
4
- import { ErrorCode } from '@directus/errors';
5
4
  import { getFlowManager } from '../flows.js';
6
5
  import { respond } from '../middleware/respond.js';
7
6
  import useCollection from '../middleware/use-collection.js';
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,15 +1,14 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, ForbiddenError, RouteNotFoundError, isDirectusError } from '@directus/errors';
2
+ import { isSystemCollection } from '@directus/system-data';
2
3
  import express from 'express';
3
- import { ErrorCode, ForbiddenError, RouteNotFoundError } from '@directus/errors';
4
4
  import collectionExists from '../middleware/collection-exists.js';
5
+ import { mergeContentVersions } from '../middleware/merge-content-versions.js';
5
6
  import { respond } from '../middleware/respond.js';
6
7
  import { validateBatch } from '../middleware/validate-batch.js';
7
- import { mergeContentVersions } from '../middleware/merge-content-versions.js';
8
8
  import { ItemsService } from '../services/items.js';
9
9
  import { MetaService } from '../services/meta.js';
10
10
  import asyncHandler from '../utils/async-handler.js';
11
11
  import { sanitizeQuery } from '../utils/sanitize-query.js';
12
- import { isSystemCollection } from '@directus/system-data';
13
12
  const router = express.Router();
14
13
  router.post('/:collection', collectionExists, asyncHandler(async (req, res, next) => {
15
14
  if (isSystemCollection(req.params['collection']))
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,6 +1,5 @@
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
1
2
  import express from 'express';
2
- import { isDirectusError } from '@directus/errors';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, isDirectusError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,7 +1,6 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, ForbiddenError, InvalidCredentialsError, InvalidPayloadError, isDirectusError, } from '@directus/errors';
2
2
  import express from 'express';
3
3
  import Joi from 'joi';
4
- import { ErrorCode, ForbiddenError, InvalidCredentialsError, InvalidPayloadError } from '@directus/errors';
5
4
  import { respond } from '../middleware/respond.js';
6
5
  import useCollection from '../middleware/use-collection.js';
7
6
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -1,6 +1,5 @@
1
- import { isDirectusError } from '@directus/errors';
1
+ import { ErrorCode, createError } from '@directus/errors';
2
2
  import express from 'express';
3
- import { ErrorCode } from '@directus/errors';
4
3
  import { respond } from '../middleware/respond.js';
5
4
  import useCollection from '../middleware/use-collection.js';
6
5
  import { validateBatch } from '../middleware/validate-batch.js';
@@ -10,37 +9,9 @@ import asyncHandler from '../utils/async-handler.js';
10
9
  import { sanitizeQuery } from '../utils/sanitize-query.js';
11
10
  const router = express.Router();
12
11
  router.use(useCollection('directus_webhooks'));
13
- router.post('/', asyncHandler(async (req, res, next) => {
14
- const service = new WebhooksService({
15
- accountability: req.accountability,
16
- schema: req.schema,
17
- });
18
- const savedKeys = [];
19
- if (Array.isArray(req.body)) {
20
- const keys = await service.createMany(req.body);
21
- savedKeys.push(...keys);
22
- }
23
- else {
24
- const key = await service.createOne(req.body);
25
- savedKeys.push(key);
26
- }
27
- try {
28
- if (Array.isArray(req.body)) {
29
- const items = await service.readMany(savedKeys, req.sanitizedQuery);
30
- res.locals['payload'] = { data: items };
31
- }
32
- else {
33
- const item = await service.readOne(savedKeys[0], req.sanitizedQuery);
34
- res.locals['payload'] = { data: item };
35
- }
36
- }
37
- catch (error) {
38
- if (isDirectusError(error, ErrorCode.Forbidden)) {
39
- return next();
40
- }
41
- throw error;
42
- }
43
- return next();
12
+ router.post('/', asyncHandler(async (_req, _res, _next) => {
13
+ // Disallow creation of new Webhooks as part of the deprecation, see https://github.com/directus/directus/issues/15553
14
+ throw new (createError(ErrorCode.MethodNotAllowed, 'Webhooks are deprecated, use Flows instead', 405))();
44
15
  }), respond);
45
16
  const readHandler = asyncHandler(async (req, res, next) => {
46
17
  const service = new WebhooksService({
@@ -67,48 +38,13 @@ router.get('/:pk', asyncHandler(async (req, res, next) => {
67
38
  res.locals['payload'] = { data: record || null };
68
39
  return next();
69
40
  }), respond);
70
- router.patch('/', validateBatch('update'), asyncHandler(async (req, res, next) => {
71
- const service = new WebhooksService({
72
- accountability: req.accountability,
73
- schema: req.schema,
74
- });
75
- let keys = [];
76
- if (req.body.keys) {
77
- keys = await service.updateMany(req.body.keys, req.body.data);
78
- }
79
- else {
80
- const sanitizedQuery = sanitizeQuery(req.body.query, req.accountability);
81
- keys = await service.updateByQuery(sanitizedQuery, req.body.data);
82
- }
83
- try {
84
- const result = await service.readMany(keys, req.sanitizedQuery);
85
- res.locals['payload'] = { data: result };
86
- }
87
- catch (error) {
88
- if (isDirectusError(error, ErrorCode.Forbidden)) {
89
- return next();
90
- }
91
- throw error;
92
- }
93
- return next();
41
+ router.patch('/', validateBatch('update'), asyncHandler(async (_req, _res, _next) => {
42
+ // Disallow patching of Webhooks as part of the deprecation, see https://github.com/directus/directus/issues/15553
43
+ throw new (createError(ErrorCode.MethodNotAllowed, 'Webhooks are deprecated, use Flows instead', 405))();
94
44
  }), respond);
95
- router.patch('/:pk', asyncHandler(async (req, res, next) => {
96
- const service = new WebhooksService({
97
- accountability: req.accountability,
98
- schema: req.schema,
99
- });
100
- const primaryKey = await service.updateOne(req.params['pk'], req.body);
101
- try {
102
- const item = await service.readOne(primaryKey, req.sanitizedQuery);
103
- res.locals['payload'] = { data: item || null };
104
- }
105
- catch (error) {
106
- if (isDirectusError(error, ErrorCode.Forbidden)) {
107
- return next();
108
- }
109
- throw error;
110
- }
111
- return next();
45
+ router.patch('/:pk', asyncHandler(async (_req, _res, _next) => {
46
+ // Disallow patching of Webhooks as part of the deprecation, see https://github.com/directus/directus/issues/15553
47
+ throw new (createError(ErrorCode.MethodNotAllowed, 'Webhooks are deprecated, use Flows instead', 405))();
112
48
  }), respond);
113
49
  router.delete('/', asyncHandler(async (req, _res, next) => {
114
50
  const service = new WebhooksService({
@@ -0,0 +1,3 @@
1
+ import type { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
@@ -0,0 +1,14 @@
1
+ export async function up(knex) {
2
+ await knex.schema.alterTable('directus_settings', (table) => {
3
+ table.string('report_error_url').nullable();
4
+ table.string('report_bug_url').nullable();
5
+ table.string('report_feature_url').nullable();
6
+ });
7
+ }
8
+ export async function down(knex) {
9
+ await knex.schema.alterTable('directus_settings', (table) => {
10
+ table.dropColumn('report_error_url');
11
+ table.dropColumn('report_bug_url');
12
+ table.dropColumn('report_feature_url');
13
+ });
14
+ }
@@ -32,7 +32,7 @@ export async function up(knex) {
32
32
  source = 'local';
33
33
  }
34
34
  await knex('directus_extensions').update({ id, source, folder: name }).where({ name });
35
- idMap.set(name, id);
35
+ idMap.set(name, { id, source });
36
36
  }
37
37
  }
38
38
  for (const { name } of installedExtensions) {
@@ -44,16 +44,28 @@ export async function up(knex) {
44
44
  continue;
45
45
  const isScopedModuleBundleChild = name.startsWith('@') && splittedName.length > 2;
46
46
  const bundleParentName = isScopedModuleBundleParent || isScopedModuleBundleChild ? splittedName.slice(0, 2).join('/') : splittedName[0];
47
- const bundleParentId = idMap.get(bundleParentName);
48
- if (!bundleParentId)
47
+ const bundleParent = idMap.get(bundleParentName);
48
+ if (!bundleParent)
49
49
  continue;
50
50
  await knex('directus_extensions')
51
- .update({ bundle: bundleParentId, folder: name.substring(bundleParentName.length + 1) })
51
+ .update({
52
+ bundle: bundleParent.id,
53
+ folder: name.substring(bundleParentName.length + 1),
54
+ source: bundleParent.source,
55
+ })
52
56
  .where({ folder: name });
53
57
  }
58
+ await knex.schema.alterTable('directus_extensions', (table) => {
59
+ table.uuid('id').alter().notNullable();
60
+ });
61
+ await knex.transaction(async (trx) => {
62
+ await trx.schema.alterTable('directus_extensions', (table) => {
63
+ table.dropPrimary();
64
+ table.primary(['id']);
65
+ });
66
+ });
54
67
  await knex.schema.alterTable('directus_extensions', (table) => {
55
68
  table.dropColumn('name');
56
- table.uuid('id').alter().primary().notNullable();
57
69
  table.string('source').alter().notNullable();
58
70
  table.string('folder').alter().notNullable();
59
71
  });
@@ -0,0 +1,3 @@
1
+ import type { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { getHelpers } from '../helpers/index.js';
2
+ export async function up(knex) {
3
+ const helper = getHelpers(knex).schema;
4
+ await Promise.all([
5
+ helper.changeToType('directus_activity', 'user_agent', 'text'),
6
+ helper.changeToType('directus_sessions', 'user_agent', 'text'),
7
+ ]);
8
+ }
9
+ export async function down(knex) {
10
+ const helper = await getHelpers(knex).schema;
11
+ const opts = {
12
+ nullable: false,
13
+ length: 255,
14
+ };
15
+ await Promise.all([
16
+ helper.changeToType('directus_activity', 'user_agent', 'string', opts),
17
+ helper.changeToType('directus_sessions', 'user_agent', 'string', opts),
18
+ ]);
19
+ }
@@ -0,0 +1,13 @@
1
+ import type { Knex } from 'knex';
2
+ /**
3
+ * 0. Identify and persist which webhooks were active before deprecation
4
+ * 1. Migrate existing webhooks over to identically behaving Flows
5
+ * 2. Disable existing webhooks
6
+ * 3. Dont drop webhooks yet
7
+ */
8
+ export declare function up(knex: Knex): Promise<void>;
9
+ /**
10
+ * Dont completely drop Webhooks yet.
11
+ * Lets preserve the data and drop them in the next release to be extra safe with users data.
12
+ */
13
+ export declare function down(knex: Knex): Promise<void>;