@strapi/strapi 4.11.0-beta.0 → 4.11.0-exp.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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { cloneDeep } = require('lodash/fp');
4
4
  const _ = require('lodash');
5
- const { hasDraftAndPublish, getPrivateAttributes } = require('@strapi/utils').contentTypes;
5
+ const { hasDraftAndPublish } = require('@strapi/utils').contentTypes;
6
6
  const {
7
7
  CREATED_AT_ATTRIBUTE,
8
8
  UPDATED_AT_ATTRIBUTE,
@@ -58,12 +58,6 @@ const createContentType = (uid, definition) => {
58
58
  );
59
59
  }
60
60
 
61
- Object.defineProperty(schema, 'privateAttributes', {
62
- get() {
63
- return getPrivateAttributes(schema);
64
- },
65
- });
66
-
67
61
  // attributes
68
62
  Object.assign(schema.attributes, {
69
63
  [CREATED_AT_ATTRIBUTE]: {
@@ -1,8 +1,6 @@
1
- import { Database } from '@strapi/database';
1
+ import type { Database, ID } from '@strapi/database';
2
2
  import { Strapi } from '../../';
3
3
 
4
- type ID = number | string;
5
-
6
4
  type EntityServiceAction =
7
5
  | 'findMany'
8
6
  | 'findPage'
@@ -4,11 +4,7 @@ const _ = require('lodash');
4
4
  const delegate = require('delegates');
5
5
  const { InvalidTimeError, InvalidDateError, InvalidDateTimeError, InvalidRelationError } =
6
6
  require('@strapi/database').errors;
7
- const {
8
- webhook: webhookUtils,
9
- contentTypes: contentTypesUtils,
10
- sanitize,
11
- } = require('@strapi/utils');
7
+ const { contentTypes: contentTypesUtils, sanitize } = require('@strapi/utils');
12
8
  const { ValidationError } = require('@strapi/utils').errors;
13
9
  const { isAnyToMany } = require('@strapi/utils').relations;
14
10
  const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams;
@@ -31,9 +27,6 @@ const transformLoadParamsToQuery = (uid, field, params = {}, pagination = {}) =>
31
27
  };
32
28
  };
33
29
 
34
- // TODO: those should be strapi events used by the webhooks not the other way arround
35
- const { ENTRY_CREATE, ENTRY_UPDATE, ENTRY_DELETE } = webhookUtils.webhookEvents;
36
-
37
30
  const databaseErrorsToTransform = [
38
31
  InvalidTimeError,
39
32
  InvalidDateTimeError,
@@ -49,6 +42,12 @@ const updatePipeline = (data, context) => {
49
42
  return applyTransforms(data, context);
50
43
  };
51
44
 
45
+ const ALLOWED_WEBHOOK_EVENTS = {
46
+ ENTRY_CREATE: 'entry.create',
47
+ ENTRY_UPDATE: 'entry.update',
48
+ ENTRY_DELETE: 'entry.delete',
49
+ };
50
+
52
51
  /**
53
52
  * @type {import('.').default}
54
53
  */
@@ -59,6 +58,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
59
58
  return options;
60
59
  },
61
60
 
61
+ async wrapResult(result) {
62
+ return result;
63
+ },
64
+
62
65
  async emitEvent(uid, event, entity) {
63
66
  // Ignore audit log events to prevent infinite loops
64
67
  if (uid === 'admin::audit-log') {
@@ -83,10 +86,12 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
83
86
  const query = transformParamsToQuery(uid, wrappedParams);
84
87
 
85
88
  if (kind === 'singleType') {
86
- return db.query(uid).findOne(query);
89
+ const entity = db.query(uid).findOne(query);
90
+ return this.wrapResult(entity, { uid, action: 'findOne' });
87
91
  }
88
92
 
89
- return db.query(uid).findMany(query);
93
+ const entities = await db.query(uid).findMany(query);
94
+ return this.wrapResult(entities, { uid, action: 'findMany' });
90
95
  },
91
96
 
92
97
  async findPage(uid, opts) {
@@ -94,7 +99,11 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
94
99
 
95
100
  const query = transformParamsToQuery(uid, wrappedParams);
96
101
 
97
- return db.query(uid).findPage(query);
102
+ const page = await db.query(uid).findPage(query);
103
+ return {
104
+ ...page,
105
+ results: await this.wrapResult(page.results, { uid, action: 'findPage' }),
106
+ };
98
107
  },
99
108
 
100
109
  // TODO: streamline the logic based on the populate option
@@ -103,7 +112,11 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
103
112
 
104
113
  const query = transformParamsToQuery(uid, wrappedParams);
105
114
 
106
- return db.query(uid).findPage(query);
115
+ const entities = await db.query(uid).findPage(query);
116
+ return {
117
+ ...entities,
118
+ results: await this.wrapResult(entities.results, { uid, action: 'findWithRelationCounts' }),
119
+ };
107
120
  },
108
121
 
109
122
  async findWithRelationCounts(uid, opts) {
@@ -111,7 +124,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
111
124
 
112
125
  const query = transformParamsToQuery(uid, wrappedParams);
113
126
 
114
- return db.query(uid).findMany(query);
127
+ const entities = await db.query(uid).findMany(query);
128
+ return this.wrapResult(entities, { uid, action: 'findWithRelationCounts' });
115
129
  },
116
130
 
117
131
  async findOne(uid, entityId, opts) {
@@ -119,7 +133,8 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
119
133
 
120
134
  const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
121
135
 
122
- return db.query(uid).findOne({ ...query, where: { id: entityId } });
136
+ const entity = await db.query(uid).findOne({ ...query, where: { id: entityId } });
137
+ return this.wrapResult(entity, { uid, action: 'findOne' });
123
138
  },
124
139
 
125
140
  async count(uid, opts) {
@@ -162,6 +177,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
162
177
  entity = await this.findOne(uid, entity.id, wrappedParams);
163
178
  }
164
179
 
180
+ entity = await this.wrapResult(entity, { uid, action: 'create' });
181
+
182
+ const { ENTRY_CREATE } = ALLOWED_WEBHOOK_EVENTS;
165
183
  await this.emitEvent(uid, ENTRY_CREATE, entity);
166
184
 
167
185
  return entity;
@@ -213,6 +231,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
213
231
  entity = await this.findOne(uid, entity.id, wrappedParams);
214
232
  }
215
233
 
234
+ entity = await this.wrapResult(entity, { uid, action: 'update' });
235
+
236
+ const { ENTRY_UPDATE } = ALLOWED_WEBHOOK_EVENTS;
216
237
  await this.emitEvent(uid, ENTRY_UPDATE, entity);
217
238
 
218
239
  return entity;
@@ -224,7 +245,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
224
245
  // select / populate
225
246
  const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
226
247
 
227
- const entityToDelete = await db.query(uid).findOne({
248
+ let entityToDelete = await db.query(uid).findOne({
228
249
  ...query,
229
250
  where: { id: entityId },
230
251
  });
@@ -238,6 +259,9 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
238
259
  await db.query(uid).delete({ where: { id: entityToDelete.id } });
239
260
  await deleteComponents(uid, componentsToDelete, { loadComponents: false });
240
261
 
262
+ entityToDelete = await this.wrapResult(entityToDelete, { uid, action: 'delete' });
263
+
264
+ const { ENTRY_DELETE } = ALLOWED_WEBHOOK_EVENTS;
241
265
  await this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
242
266
 
243
267
  return entityToDelete;
@@ -250,7 +274,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
250
274
  // select / populate
251
275
  const query = transformParamsToQuery(uid, wrappedParams);
252
276
 
253
- const entitiesToDelete = await db.query(uid).findMany(query);
277
+ let entitiesToDelete = await db.query(uid).findMany(query);
254
278
 
255
279
  if (!entitiesToDelete.length) {
256
280
  return null;
@@ -265,21 +289,28 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
265
289
  componentsToDelete.map((compos) => deleteComponents(uid, compos, { loadComponents: false }))
266
290
  );
267
291
 
292
+ entitiesToDelete = await this.wrapResult(entitiesToDelete, { uid, action: 'delete' });
293
+
268
294
  // Trigger webhooks. One for each entity
295
+ const { ENTRY_DELETE } = ALLOWED_WEBHOOK_EVENTS;
269
296
  await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity)));
270
297
 
271
298
  return deletedEntities;
272
299
  },
273
300
 
274
- load(uid, entity, field, params = {}) {
301
+ async load(uid, entity, field, params = {}) {
275
302
  if (!_.isString(field)) {
276
303
  throw new Error(`Invalid load. Expected "${field}" to be a string`);
277
304
  }
278
305
 
279
- return db.query(uid).load(entity, field, transformLoadParamsToQuery(uid, field, params));
306
+ const loadedEntity = await db
307
+ .query(uid)
308
+ .load(entity, field, transformLoadParamsToQuery(uid, field, params));
309
+
310
+ return this.wrapResult(loadedEntity, { uid, field, action: 'load' });
280
311
  },
281
312
 
282
- loadPages(uid, entity, field, params = {}, pagination = {}) {
313
+ async loadPages(uid, entity, field, params = {}, pagination = {}) {
283
314
  if (!_.isString(field)) {
284
315
  throw new Error(`Invalid load. Expected "${field}" to be a string`);
285
316
  }
@@ -293,11 +324,20 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
293
324
 
294
325
  const query = transformLoadParamsToQuery(uid, field, params, pagination);
295
326
 
296
- return db.query(uid).loadPages(entity, field, query);
327
+ const loadedPage = await db.query(uid).loadPages(entity, field, query);
328
+
329
+ return {
330
+ ...loadedPage,
331
+ results: await this.wrapResult(loadedPage.results, { uid, field, action: 'load' }),
332
+ };
297
333
  },
298
334
  });
299
335
 
300
336
  module.exports = (ctx) => {
337
+ Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
338
+ ctx.strapi.webhookStore.addAllowedEvent(key, value);
339
+ });
340
+
301
341
  const implementation = createDefaultImplementation(ctx);
302
342
 
303
343
  const service = {
@@ -4,6 +4,9 @@
4
4
 
5
5
  'use strict';
6
6
 
7
+ const { mapAsync } = require('@strapi/utils');
8
+ const { ValidationError } = require('@strapi/utils').errors;
9
+
7
10
  const webhookModel = {
8
11
  uid: 'webhook',
9
12
  collectionName: 'strapi_webhooks',
@@ -47,30 +50,56 @@ const fromDBObject = (row) => {
47
50
  };
48
51
  };
49
52
 
53
+ const webhookEventValidator = async (allowedEvents, events) => {
54
+ const allowedValues = Array.from(allowedEvents.values());
55
+
56
+ await mapAsync(events, (event) => {
57
+ if (allowedValues.includes(event)) {
58
+ return;
59
+ }
60
+
61
+ throw new ValidationError(`Webhook event ${event} is not supported`);
62
+ });
63
+ };
64
+
50
65
  const createWebhookStore = ({ db }) => {
51
66
  const webhookQueries = db.query('webhook');
52
67
 
53
68
  return {
69
+ allowedEvents: new Map([]),
70
+ addAllowedEvent(key, value) {
71
+ this.allowedEvents.set(key, value);
72
+ },
73
+ removeAllowedEvent(key) {
74
+ this.allowedEvents.delete(key);
75
+ },
76
+ listAllowedEvents() {
77
+ return Array.from(this.allowedEvents.keys());
78
+ },
79
+ getAllowedEvent(key) {
80
+ return this.allowedEvents.get(key);
81
+ },
54
82
  async findWebhooks() {
55
83
  const results = await webhookQueries.findMany();
56
84
 
57
85
  return results.map(fromDBObject);
58
86
  },
59
-
60
87
  async findWebhook(id) {
61
88
  const result = await webhookQueries.findOne({ where: { id } });
62
89
  return result ? fromDBObject(result) : null;
63
90
  },
91
+ async createWebhook(data) {
92
+ await webhookEventValidator(this.allowedEvents, data.events);
64
93
 
65
- createWebhook(data) {
66
94
  return webhookQueries
67
95
  .create({
68
96
  data: toDBObject({ ...data, isEnabled: true }),
69
97
  })
70
98
  .then(fromDBObject);
71
99
  },
72
-
73
100
  async updateWebhook(id, data) {
101
+ await webhookEventValidator(this.allowedEvents, data.events);
102
+
74
103
  const webhook = await webhookQueries.update({
75
104
  where: { id },
76
105
  data: toDBObject(data),
@@ -78,7 +107,6 @@ const createWebhookStore = ({ db }) => {
78
107
 
79
108
  return webhook ? fromDBObject(webhook) : null;
80
109
  },
81
-
82
110
  async deleteWebhook(id) {
83
111
  const webhook = await webhookQueries.delete({ where: { id } });
84
112
  return webhook ? fromDBObject(webhook) : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/strapi",
3
- "version": "4.11.0-beta.0",
3
+ "version": "4.11.0-exp.0",
4
4
  "description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite",
5
5
  "keywords": [
6
6
  "strapi",
@@ -81,19 +81,19 @@
81
81
  "dependencies": {
82
82
  "@koa/cors": "3.4.3",
83
83
  "@koa/router": "10.1.1",
84
- "@strapi/admin": "4.11.0-beta.0",
85
- "@strapi/data-transfer": "4.11.0-beta.0",
86
- "@strapi/database": "4.11.0-beta.0",
87
- "@strapi/generate-new": "4.11.0-beta.0",
88
- "@strapi/generators": "4.11.0-beta.0",
89
- "@strapi/logger": "4.11.0-beta.0",
90
- "@strapi/permissions": "4.11.0-beta.0",
91
- "@strapi/plugin-content-manager": "4.11.0-beta.0",
92
- "@strapi/plugin-content-type-builder": "4.11.0-beta.0",
93
- "@strapi/plugin-email": "4.11.0-beta.0",
94
- "@strapi/plugin-upload": "4.11.0-beta.0",
95
- "@strapi/typescript-utils": "4.11.0-beta.0",
96
- "@strapi/utils": "4.11.0-beta.0",
84
+ "@strapi/admin": "4.11.0-exp.0",
85
+ "@strapi/data-transfer": "4.11.0-exp.0",
86
+ "@strapi/database": "4.11.0-exp.0",
87
+ "@strapi/generate-new": "4.11.0-exp.0",
88
+ "@strapi/generators": "4.11.0-exp.0",
89
+ "@strapi/logger": "4.11.0-exp.0",
90
+ "@strapi/permissions": "4.11.0-exp.0",
91
+ "@strapi/plugin-content-manager": "4.11.0-exp.0",
92
+ "@strapi/plugin-content-type-builder": "4.11.0-exp.0",
93
+ "@strapi/plugin-email": "4.11.0-exp.0",
94
+ "@strapi/plugin-upload": "4.11.0-exp.0",
95
+ "@strapi/typescript-utils": "4.11.0-exp.0",
96
+ "@strapi/utils": "4.11.0-exp.0",
97
97
  "bcryptjs": "2.4.3",
98
98
  "boxen": "5.1.2",
99
99
  "chalk": "4.1.2",
@@ -136,11 +136,11 @@
136
136
  },
137
137
  "devDependencies": {
138
138
  "supertest": "6.3.3",
139
- "typescript": "5.0.4"
139
+ "typescript": "5.1.3"
140
140
  },
141
141
  "engines": {
142
142
  "node": ">=14.19.1 <=18.x.x",
143
143
  "npm": ">=6.0.0"
144
144
  },
145
- "gitHead": "fd63eb0f5c625311803775504cec0d3d4d770da9"
145
+ "gitHead": "8357aab46ebea3565c44744eb137ed36602a4306"
146
146
  }