@directus/api 12.0.3 → 12.1.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.
@@ -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,12 @@
1
+ export async function up(knex) {
2
+ await knex.schema.alterTable('directus_shares', (table) => {
3
+ table.dropNullable('collection');
4
+ table.dropNullable('item');
5
+ });
6
+ }
7
+ export async function down(knex) {
8
+ await knex.schema.alterTable('directus_shares', (table) => {
9
+ table.setNullable('collection');
10
+ table.setNullable('item');
11
+ });
12
+ }
@@ -35,7 +35,7 @@ fields:
35
35
  iconRight: lock
36
36
  masked: true
37
37
  width: half
38
- note: $t:shared_leave_blank_for_unlimited
38
+ note: $t:shared_leave_blank_for_passwordless_access
39
39
 
40
40
  - field: date_start
41
41
  width: half
@@ -12,20 +12,7 @@ const errorHandler = (err, req, res, _next) => {
12
12
  errors: [],
13
13
  };
14
14
  const errors = toArray(err);
15
- if (errors.some((err) => isDirectusError(err) === false)) {
16
- res.status(500);
17
- }
18
- else {
19
- let status = errors[0].status;
20
- for (const err of errors) {
21
- if (status !== err.status) {
22
- // If there's multiple different status codes in the errors, use 500
23
- status = 500;
24
- break;
25
- }
26
- }
27
- res.status(status);
28
- }
15
+ let status = null;
29
16
  for (const err of errors) {
30
17
  if (env['NODE_ENV'] === 'development') {
31
18
  err.extensions = {
@@ -35,7 +22,12 @@ const errorHandler = (err, req, res, _next) => {
35
22
  }
36
23
  if (isDirectusError(err)) {
37
24
  logger.debug(err);
38
- res.status(err.status);
25
+ if (!status) {
26
+ status = err.status;
27
+ }
28
+ else if (status !== err.status) {
29
+ status = 500;
30
+ }
39
31
  payload.errors.push({
40
32
  message: err.message,
41
33
  extensions: {
@@ -49,7 +41,7 @@ const errorHandler = (err, req, res, _next) => {
49
41
  }
50
42
  else {
51
43
  logger.error(err);
52
- res.status(500);
44
+ status = 500;
53
45
  if (req.accountability?.admin === true) {
54
46
  payload = {
55
47
  errors: [
@@ -77,6 +69,7 @@ const errorHandler = (err, req, res, _next) => {
77
69
  }
78
70
  }
79
71
  }
72
+ res.status(status ?? 500);
80
73
  emitter
81
74
  .emitFilter('request.error', payload.errors, {}, {
82
75
  database: getDatabase(),
@@ -3,14 +3,20 @@ import type { GraphQLResolveInfo } from 'graphql';
3
3
  export declare function bindPubSub(): void;
4
4
  export declare function createSubscriptionGenerator(self: GraphQLService, event: string): (_x: unknown, _y: unknown, _z: unknown, request: GraphQLResolveInfo) => AsyncGenerator<{
5
5
  [x: string]: {
6
- key: any;
7
- data: import("../../types/items.js").Item;
8
- event: string;
6
+ key: string | number;
7
+ data: null;
8
+ event: "delete";
9
9
  };
10
10
  } | {
11
11
  [x: string]: {
12
- key: any;
13
- data: null;
14
- event: string;
12
+ key: string | number;
13
+ data: any;
14
+ event: "create";
15
+ };
16
+ } | {
17
+ [x: string]: {
18
+ key: string | number;
19
+ data: any;
20
+ event: "update";
15
21
  };
16
22
  }, void, unknown>;
@@ -1,7 +1,8 @@
1
1
  import { EventEmitter, on } from 'events';
2
2
  import { getMessenger } from '../../messenger.js';
3
3
  import { getSchema } from '../../utils/get-schema.js';
4
- import { ItemsService } from '../items.js';
4
+ import { refreshAccountability } from '../../websocket/authenticate.js';
5
+ import { getSinglePayload } from '../../websocket/utils/items.js';
5
6
  const messages = createPubSub(new EventEmitter());
6
7
  export function bindPubSub() {
7
8
  const messenger = getMessenger();
@@ -18,25 +19,51 @@ export function createSubscriptionGenerator(self, event) {
18
19
  if ('event' in args && eventData['action'] !== args['event']) {
19
20
  continue; // skip filtered events
20
21
  }
22
+ const accountability = await refreshAccountability(self.accountability);
21
23
  const schema = await getSchema();
22
- if (eventData['action'] === 'create') {
23
- const { collection, key } = eventData;
24
- const service = new ItemsService(collection, { schema });
25
- const data = await service.readOne(key, { fields });
26
- yield { [event]: { key, data, event: 'create' } };
24
+ const subscription = {
25
+ collection: eventData['collection'],
26
+ event: eventData['action'],
27
+ query: { fields },
28
+ };
29
+ if (eventData['action'] === 'delete') {
30
+ // we have no data to send besides the key
31
+ for (const key of eventData.keys) {
32
+ yield { [event]: { key, data: null, event: eventData['action'] } };
33
+ }
27
34
  }
28
- if (eventData['action'] === 'update') {
29
- const { collection, keys } = eventData;
30
- const service = new ItemsService(collection, { schema });
31
- for (const key of keys) {
32
- const data = await service.readOne(key, { fields });
33
- yield { [event]: { key, data, event: 'update' } };
35
+ if (eventData['action'] === 'create') {
36
+ try {
37
+ subscription.item = eventData['key'];
38
+ const result = await getSinglePayload(subscription, accountability, schema, eventData);
39
+ yield {
40
+ [event]: {
41
+ key: eventData['key'],
42
+ data: result['data'],
43
+ event: eventData['action'],
44
+ },
45
+ };
46
+ }
47
+ catch {
48
+ // dont notify the subscription of permission errors
34
49
  }
35
50
  }
36
- if (eventData['action'] === 'delete') {
37
- const { keys } = eventData;
38
- for (const key of keys) {
39
- yield { [event]: { key, data: null, event: 'delete' } };
51
+ if (eventData['action'] === 'update') {
52
+ for (const key of eventData['keys']) {
53
+ try {
54
+ subscription.item = key;
55
+ const result = await getSinglePayload(subscription, accountability, schema, eventData);
56
+ yield {
57
+ [event]: {
58
+ key,
59
+ data: result['data'],
60
+ event: eventData['action'],
61
+ },
62
+ };
63
+ }
64
+ catch {
65
+ // dont notify the subscription of permission errors
66
+ }
40
67
  }
41
68
  }
42
69
  }
@@ -169,6 +169,11 @@ export class ExportService {
169
169
  schema: this.schema,
170
170
  knex: trx,
171
171
  });
172
+ const { primary } = this.schema.collections[collection];
173
+ const sort = query.sort ?? [];
174
+ if (sort.includes(primary) === false) {
175
+ sort.push(primary);
176
+ }
172
177
  const totalCount = await service
173
178
  .readByQuery({
174
179
  ...query,
@@ -188,6 +193,7 @@ export class ExportService {
188
193
  }
189
194
  const result = await service.readByQuery({
190
195
  ...query,
196
+ sort,
191
197
  limit,
192
198
  offset: batch * env['EXPORT_BATCH_SIZE'],
193
199
  });
@@ -35,7 +35,7 @@ a[x-apple-data-detectors] {
35
35
  line-height: inherit !important;
36
36
  }
37
37
  body a {
38
- color: #6644ff;
38
+ color: {{projectColor}};
39
39
  text-decoration: none;
40
40
  }
41
41
  hr {
@@ -74,7 +74,7 @@ hr {
74
74
  color: #FFFFFF !important;
75
75
  }
76
76
  .link {
77
- color: #6644ff !important;
77
+ color: {{projectColor}} !important;
78
78
  }
79
79
  .button {
80
80
  background-color:#0BA582 !important;
@@ -42,8 +42,9 @@ export class MetaService {
42
42
  return Number(result?.count ?? 0);
43
43
  }
44
44
  async filterCount(collection, query) {
45
- const dbQuery = this.knex(collection).count('*', { as: 'count' });
45
+ const dbQuery = this.knex(collection);
46
46
  let filter = query.filter || {};
47
+ let hasJoins = false;
47
48
  if (this.accountability?.admin !== true) {
48
49
  const permissionsRecord = this.accountability?.permissions?.find((permission) => {
49
50
  return permission.action === 'read' && permission.collection === collection;
@@ -59,12 +60,19 @@ export class MetaService {
59
60
  }
60
61
  }
61
62
  if (Object.keys(filter).length > 0) {
62
- applyFilter(this.knex, this.schema, dbQuery, filter, collection, {});
63
+ ({ hasJoins } = applyFilter(this.knex, this.schema, dbQuery, filter, collection, {}));
63
64
  }
64
65
  if (query.search) {
65
66
  applySearch(this.schema, dbQuery, query.search, collection);
66
67
  }
68
+ if (hasJoins) {
69
+ const primaryKeyName = this.schema.collections[collection].primary;
70
+ dbQuery.countDistinct({ count: [`${collection}.${primaryKeyName}`] });
71
+ }
72
+ else {
73
+ dbQuery.count('*', { as: 'count' });
74
+ }
67
75
  const records = await dbQuery;
68
- return Number(records[0].count);
76
+ return Number(records[0]['count']);
69
77
  }
70
78
  }
@@ -1,6 +1,7 @@
1
1
  export const _aliasMap = {
2
2
  local: '@directus/storage-driver-local',
3
3
  s3: '@directus/storage-driver-s3',
4
+ supabase: '@directus/storage-driver-supabase',
4
5
  gcs: '@directus/storage-driver-gcs',
5
6
  azure: '@directus/storage-driver-azure',
6
7
  cloudinary: '@directus/storage-driver-cloudinary',
@@ -5,6 +5,7 @@ export declare class Url {
5
5
  path: string[];
6
6
  query: Record<string, string>;
7
7
  hash: string | null;
8
+ hasTrailingSlash: boolean;
8
9
  constructor(url: string);
9
10
  isAbsolute(): boolean;
10
11
  isProtocolRelative(): boolean;
package/dist/utils/url.js CHANGED
@@ -6,6 +6,7 @@ export class Url {
6
6
  path;
7
7
  query;
8
8
  hash;
9
+ hasTrailingSlash;
9
10
  constructor(url) {
10
11
  const parsedUrl = new URL(url, 'http://localhost');
11
12
  const isProtocolRelative = /^\/\//.test(url);
@@ -20,6 +21,7 @@ export class Url {
20
21
  this.path = parsedUrl.pathname.split('/').filter((p) => p !== '');
21
22
  this.query = Object.fromEntries(parsedUrl.searchParams.entries());
22
23
  this.hash = parsedUrl.hash !== '' ? parsedUrl.hash.substring(1) : null;
24
+ this.hasTrailingSlash = parsedUrl.pathname.length > 1 ? parsedUrl.pathname.endsWith('/') : url.endsWith('/');
23
25
  }
24
26
  isAbsolute() {
25
27
  return this.protocol !== null && this.host !== null;
@@ -52,8 +54,9 @@ export class Url {
52
54
  const port = this.port !== null ? `:${this.port}` : '';
53
55
  const origin = `${this.host !== null ? `${protocol}//` : ''}${host}${port}`;
54
56
  const path = this.path.length ? `/${this.path.join('/')}` : '';
57
+ const trailingSlash = this.hasTrailingSlash ? '/' : '';
55
58
  const query = Object.keys(this.query).length !== 0 ? `?${new URLSearchParams(this.query).toString()}` : '';
56
59
  const hash = this.hash !== null ? `#${this.hash}` : '';
57
- return `${!rootRelative ? origin : ''}${path}${query}${hash}`;
60
+ return `${!rootRelative ? origin : ''}${path}${trailingSlash}${query}${hash}`;
58
61
  }
59
62
  }
@@ -9,18 +9,24 @@ export function registerWebSocketEvents() {
9
9
  'items',
10
10
  'activity',
11
11
  'collections',
12
+ 'dashboards',
12
13
  'folders',
14
+ 'notifications',
15
+ 'operations',
16
+ 'panels',
13
17
  'permissions',
14
18
  'presets',
15
19
  'revisions',
16
20
  'roles',
17
21
  'settings',
22
+ 'shares',
18
23
  'users',
19
24
  'webhooks',
20
25
  ]);
21
26
  registerFieldsHooks();
22
27
  registerFilesHooks();
23
28
  registerRelationsHooks();
29
+ registerSortHooks();
24
30
  }
25
31
  function registerActionHooks(modules) {
26
32
  // register event hooks that can be handled in an uniform manner
@@ -108,6 +114,14 @@ function registerRelationsHooks() {
108
114
  payload: { collection, fields: payload },
109
115
  }));
110
116
  }
117
+ function registerSortHooks() {
118
+ registerAction('items.sort', ({ collection, item }) => ({
119
+ collection,
120
+ action: 'update',
121
+ keys: [item],
122
+ payload: {},
123
+ }));
124
+ }
111
125
  /**
112
126
  * Wrapper for emitter.onAction to hook into system events
113
127
  * @param event The action event to watch
@@ -34,10 +34,5 @@ export declare class SubscribeHandler {
34
34
  * Handle incoming (un)subscribe requests
35
35
  */
36
36
  onMessage(client: WebSocketClient, message: WebSocketSubscribeMessage): Promise<void>;
37
- private getSinglePayload;
38
- private getMultiPayload;
39
- private getCollectionPayload;
40
- private getFieldsPayload;
41
- private getItemsPayload;
42
37
  private getSubscription;
43
38
  }
@@ -1,14 +1,13 @@
1
1
  import emitter from '../../emitter.js';
2
2
  import { InvalidPayloadError } from '../../errors/index.js';
3
3
  import { getMessenger } from '../../messenger.js';
4
- import { CollectionsService, FieldsService, MetaService } from '../../services/index.js';
5
4
  import { getSchema } from '../../utils/get-schema.js';
6
- import { getService } from '../../utils/get-service.js';
7
5
  import { sanitizeQuery } from '../../utils/sanitize-query.js';
8
6
  import { refreshAccountability } from '../authenticate.js';
9
7
  import { WebSocketError, handleWebSocketError } from '../errors.js';
10
8
  import { WebSocketSubscribeMessage } from '../messages.js';
11
9
  import { fmtMessage, getMessageType } from '../utils/message.js';
10
+ import { getMultiPayload, getSinglePayload } from '../utils/items.js';
12
11
  /**
13
12
  * Handler responsible for subscriptions
14
13
  */
@@ -108,8 +107,8 @@ export class SubscribeHandler {
108
107
  try {
109
108
  client.accountability = await refreshAccountability(client.accountability);
110
109
  const result = 'item' in subscription
111
- ? await this.getSinglePayload(subscription, client.accountability, schema, event)
112
- : await this.getMultiPayload(subscription, client.accountability, schema, event);
110
+ ? await getSinglePayload(subscription, client.accountability, schema, event)
111
+ : await getMultiPayload(subscription, client.accountability, schema, event);
113
112
  if (Array.isArray(result?.['data']) && result?.['data']?.length === 0)
114
113
  return;
115
114
  client.send(fmtMessage('subscription', result, subscription.uid));
@@ -152,8 +151,8 @@ export class SubscribeHandler {
152
151
  if (subscription.event === undefined) {
153
152
  data =
154
153
  'item' in subscription
155
- ? await this.getSinglePayload(subscription, accountability, schema)
156
- : await this.getMultiPayload(subscription, accountability, schema);
154
+ ? await getSinglePayload(subscription, accountability, schema)
155
+ : await getMultiPayload(subscription, accountability, schema);
157
156
  }
158
157
  else {
159
158
  data = { event: 'init' };
@@ -177,94 +176,6 @@ export class SubscribeHandler {
177
176
  }
178
177
  }
179
178
  }
180
- async getSinglePayload(subscription, accountability, schema, event) {
181
- const metaService = new MetaService({ schema, accountability });
182
- const query = subscription.query ?? {};
183
- const id = subscription.item;
184
- const result = {
185
- event: event?.action ?? 'init',
186
- };
187
- if (subscription.collection === 'directus_collections') {
188
- const service = new CollectionsService({ schema, accountability });
189
- result['data'] = await service.readOne(String(id));
190
- }
191
- else {
192
- const service = getService(subscription.collection, { schema, accountability });
193
- result['data'] = await service.readOne(id, query);
194
- }
195
- if ('meta' in query) {
196
- result['meta'] = await metaService.getMetaForQuery(subscription.collection, query);
197
- }
198
- return result;
199
- }
200
- async getMultiPayload(subscription, accountability, schema, event) {
201
- const metaService = new MetaService({ schema, accountability });
202
- const result = {
203
- event: event?.action ?? 'init',
204
- };
205
- switch (subscription.collection) {
206
- case 'directus_collections':
207
- result['data'] = await this.getCollectionPayload(accountability, schema, event);
208
- break;
209
- case 'directus_fields':
210
- result['data'] = await this.getFieldsPayload(accountability, schema, event);
211
- break;
212
- case 'directus_relations':
213
- result['data'] = event?.payload;
214
- break;
215
- default:
216
- result['data'] = await this.getItemsPayload(subscription, accountability, schema, event);
217
- break;
218
- }
219
- const query = subscription.query ?? {};
220
- if ('meta' in query) {
221
- result['meta'] = await metaService.getMetaForQuery(subscription.collection, query);
222
- }
223
- return result;
224
- }
225
- async getCollectionPayload(accountability, schema, event) {
226
- const service = new CollectionsService({ schema, accountability });
227
- if (!event?.action) {
228
- return await service.readByQuery();
229
- }
230
- else if (event.action === 'create') {
231
- return await service.readMany([String(event.key)]);
232
- }
233
- else if (event.action === 'delete') {
234
- return event.keys;
235
- }
236
- else {
237
- return await service.readMany(event.keys.map((key) => String(key)));
238
- }
239
- }
240
- async getFieldsPayload(accountability, schema, event) {
241
- const service = new FieldsService({ schema, accountability });
242
- if (!event?.action) {
243
- return await service.readAll();
244
- }
245
- else if (event.action === 'delete') {
246
- return event.keys;
247
- }
248
- else {
249
- return await service.readOne(event.payload?.['collection'], event.payload?.['field']);
250
- }
251
- }
252
- async getItemsPayload(subscription, accountability, schema, event) {
253
- const query = subscription.query ?? {};
254
- const service = getService(subscription.collection, { schema, accountability });
255
- if (!event?.action) {
256
- return await service.readByQuery(query);
257
- }
258
- else if (event.action === 'create') {
259
- return await service.readMany([event.key], query);
260
- }
261
- else if (event.action === 'delete') {
262
- return event.keys;
263
- }
264
- else {
265
- return await service.readMany(event.keys, query);
266
- }
267
- }
268
179
  getSubscription(client, uid) {
269
180
  for (const userSubscriptions of Object.values(this.subscriptions)) {
270
181
  for (const subscription of userSubscriptions) {
@@ -0,0 +1,53 @@
1
+ import type { Accountability, SchemaOverview } from '@directus/types';
2
+ import type { WebSocketEvent } from '../messages.js';
3
+ import type { Subscription } from '../types.js';
4
+ type PSubscription = Omit<Subscription, 'client'>;
5
+ /**
6
+ * Get a single item from a collection using the appropriate service
7
+ *
8
+ * @param subscription Subscription object
9
+ * @param accountability Accountability object
10
+ * @param schema Schema object
11
+ * @param event Event data
12
+ * @returns the fetched item
13
+ */
14
+ export declare function getSinglePayload(subscription: PSubscription, accountability: Accountability | null, schema: SchemaOverview, event?: WebSocketEvent): Promise<Record<string, any>>;
15
+ /**
16
+ * Get items from a collection using the appropriate service
17
+ *
18
+ * @param subscription Subscription object
19
+ * @param accountability Accountability object
20
+ * @param schema Schema object
21
+ * @param event Event data
22
+ * @returns the fetched items
23
+ */
24
+ export declare function getMultiPayload(subscription: PSubscription, accountability: Accountability | null, schema: SchemaOverview, event?: WebSocketEvent): Promise<Record<string, any>>;
25
+ /**
26
+ * Get collection items
27
+ *
28
+ * @param accountability Accountability object
29
+ * @param schema Schema object
30
+ * @param event Event data
31
+ * @returns the fetched collection data
32
+ */
33
+ export declare function getCollectionPayload(accountability: Accountability | null, schema: SchemaOverview, event?: WebSocketEvent): Promise<(string | number)[] | import("../../types/collection.js").Collection[]>;
34
+ /**
35
+ * Get fields items
36
+ *
37
+ * @param accountability Accountability object
38
+ * @param schema Schema object
39
+ * @param event Event data
40
+ * @returns the fetched field data
41
+ */
42
+ export declare function getFieldsPayload(accountability: Accountability | null, schema: SchemaOverview, event?: WebSocketEvent): Promise<Record<string, any> | import("@directus/types").Field[] | (string | number)[]>;
43
+ /**
44
+ * Get items from a collection using the appropriate service
45
+ *
46
+ * @param subscription Subscription object
47
+ * @param accountability Accountability object
48
+ * @param schema Schema object
49
+ * @param event Event data
50
+ * @returns the fetched data
51
+ */
52
+ export declare function getItemsPayload(subscription: PSubscription, accountability: Accountability | null, schema: SchemaOverview, event?: WebSocketEvent): Promise<(string | number)[] | import("../../types/items.js").Item[]>;
53
+ export {};
@@ -0,0 +1,133 @@
1
+ import { getService } from '../../utils/get-service.js';
2
+ import { CollectionsService, FieldsService, MetaService } from '../../services/index.js';
3
+ /**
4
+ * Get a single item from a collection using the appropriate service
5
+ *
6
+ * @param subscription Subscription object
7
+ * @param accountability Accountability object
8
+ * @param schema Schema object
9
+ * @param event Event data
10
+ * @returns the fetched item
11
+ */
12
+ export async function getSinglePayload(subscription, accountability, schema, event) {
13
+ const metaService = new MetaService({ schema, accountability });
14
+ const query = subscription.query ?? {};
15
+ const id = subscription.item;
16
+ const result = {
17
+ event: event?.action ?? 'init',
18
+ };
19
+ if (subscription.collection === 'directus_collections') {
20
+ const service = new CollectionsService({ schema, accountability });
21
+ result['data'] = await service.readOne(String(id));
22
+ }
23
+ else {
24
+ const service = getService(subscription.collection, { schema, accountability });
25
+ result['data'] = await service.readOne(id, query);
26
+ }
27
+ if ('meta' in query) {
28
+ result['meta'] = await metaService.getMetaForQuery(subscription.collection, query);
29
+ }
30
+ return result;
31
+ }
32
+ /**
33
+ * Get items from a collection using the appropriate service
34
+ *
35
+ * @param subscription Subscription object
36
+ * @param accountability Accountability object
37
+ * @param schema Schema object
38
+ * @param event Event data
39
+ * @returns the fetched items
40
+ */
41
+ export async function getMultiPayload(subscription, accountability, schema, event) {
42
+ const metaService = new MetaService({ schema, accountability });
43
+ const result = {
44
+ event: event?.action ?? 'init',
45
+ };
46
+ switch (subscription.collection) {
47
+ case 'directus_collections':
48
+ result['data'] = await getCollectionPayload(accountability, schema, event);
49
+ break;
50
+ case 'directus_fields':
51
+ result['data'] = await getFieldsPayload(accountability, schema, event);
52
+ break;
53
+ case 'directus_relations':
54
+ result['data'] = event?.payload;
55
+ break;
56
+ default:
57
+ result['data'] = await getItemsPayload(subscription, accountability, schema, event);
58
+ break;
59
+ }
60
+ const query = subscription.query ?? {};
61
+ if ('meta' in query) {
62
+ result['meta'] = await metaService.getMetaForQuery(subscription.collection, query);
63
+ }
64
+ return result;
65
+ }
66
+ /**
67
+ * Get collection items
68
+ *
69
+ * @param accountability Accountability object
70
+ * @param schema Schema object
71
+ * @param event Event data
72
+ * @returns the fetched collection data
73
+ */
74
+ export async function getCollectionPayload(accountability, schema, event) {
75
+ const service = new CollectionsService({ schema, accountability });
76
+ if (!event?.action) {
77
+ return await service.readByQuery();
78
+ }
79
+ else if (event.action === 'create') {
80
+ return await service.readMany([String(event.key)]);
81
+ }
82
+ else if (event.action === 'delete') {
83
+ return event.keys;
84
+ }
85
+ else {
86
+ return await service.readMany(event.keys.map((key) => String(key)));
87
+ }
88
+ }
89
+ /**
90
+ * Get fields items
91
+ *
92
+ * @param accountability Accountability object
93
+ * @param schema Schema object
94
+ * @param event Event data
95
+ * @returns the fetched field data
96
+ */
97
+ export async function getFieldsPayload(accountability, schema, event) {
98
+ const service = new FieldsService({ schema, accountability });
99
+ if (!event?.action) {
100
+ return await service.readAll();
101
+ }
102
+ else if (event.action === 'delete') {
103
+ return event.keys;
104
+ }
105
+ else {
106
+ return await service.readOne(event.payload?.['collection'], event.payload?.['field']);
107
+ }
108
+ }
109
+ /**
110
+ * Get items from a collection using the appropriate service
111
+ *
112
+ * @param subscription Subscription object
113
+ * @param accountability Accountability object
114
+ * @param schema Schema object
115
+ * @param event Event data
116
+ * @returns the fetched data
117
+ */
118
+ export async function getItemsPayload(subscription, accountability, schema, event) {
119
+ const query = subscription.query ?? {};
120
+ const service = getService(subscription.collection, { schema, accountability });
121
+ if (!event?.action) {
122
+ return await service.readByQuery(query);
123
+ }
124
+ else if (event.action === 'create') {
125
+ return await service.readMany([event.key], query);
126
+ }
127
+ else if (event.action === 'delete') {
128
+ return event.keys;
129
+ }
130
+ else {
131
+ return await service.readMany(event.keys, query);
132
+ }
133
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/api",
3
- "version": "12.0.3",
3
+ "version": "12.1.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,21 +143,22 @@
143
143
  "ws": "8.12.1",
144
144
  "zod": "3.21.4",
145
145
  "zod-validation-error": "1.0.1",
146
- "@directus/app": "10.5.0",
147
- "@directus/constants": "10.2.1",
148
- "@directus/errors": "0.0.1",
149
- "@directus/extensions-sdk": "10.1.6",
150
- "@directus/pressure": "1.0.6",
151
- "@directus/schema": "10.0.1",
146
+ "@directus/app": "10.6.0",
147
+ "@directus/constants": "10.2.2",
148
+ "@directus/errors": "0.0.2",
149
+ "@directus/extensions-sdk": "10.1.7",
150
+ "@directus/pressure": "1.0.7",
151
+ "@directus/schema": "10.0.2",
152
152
  "@directus/specs": "10.1.1",
153
- "@directus/storage": "10.0.4",
154
- "@directus/storage-driver-azure": "10.0.7",
155
- "@directus/storage-driver-cloudinary": "10.0.7",
156
- "@directus/storage-driver-gcs": "10.0.7",
157
- "@directus/storage-driver-local": "10.0.7",
158
- "@directus/storage-driver-s3": "10.0.7",
159
- "@directus/utils": "10.0.7",
160
- "@directus/validation": "0.0.2"
153
+ "@directus/storage": "10.0.5",
154
+ "@directus/storage-driver-azure": "10.0.8",
155
+ "@directus/storage-driver-cloudinary": "10.0.8",
156
+ "@directus/storage-driver-gcs": "10.0.8",
157
+ "@directus/storage-driver-local": "10.0.8",
158
+ "@directus/storage-driver-s3": "10.0.8",
159
+ "@directus/storage-driver-supabase": "1.0.0",
160
+ "@directus/utils": "10.0.8",
161
+ "@directus/validation": "0.0.3"
161
162
  },
162
163
  "devDependencies": {
163
164
  "@ngneat/falso": "6.4.0",
@@ -204,9 +205,9 @@
204
205
  "supertest": "6.3.3",
205
206
  "typescript": "5.0.4",
206
207
  "vitest": "0.31.1",
207
- "@directus/random": "0.2.1",
208
- "@directus/tsconfig": "0.0.7",
209
- "@directus/types": "10.1.2"
208
+ "@directus/random": "0.2.2",
209
+ "@directus/tsconfig": "1.0.0",
210
+ "@directus/types": "10.1.3"
210
211
  },
211
212
  "optionalDependencies": {
212
213
  "@keyv/redis": "2.5.8",