directus 9.11.1 → 9.12.2

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 (104) hide show
  1. package/dist/app.js +14 -1
  2. package/dist/cli/utils/create-env/env-stub.liquid +266 -9
  3. package/dist/constants.d.ts +1 -0
  4. package/dist/constants.js +5 -1
  5. package/dist/controllers/activity.js +1 -1
  6. package/dist/controllers/flows.d.ts +2 -0
  7. package/dist/controllers/flows.js +157 -0
  8. package/dist/controllers/folders.js +1 -1
  9. package/dist/controllers/notifications.js +1 -1
  10. package/dist/controllers/operations.d.ts +2 -0
  11. package/dist/controllers/operations.js +138 -0
  12. package/dist/database/helpers/fn/dialects/oracle.d.ts +9 -9
  13. package/dist/database/helpers/fn/dialects/oracle.js +22 -16
  14. package/dist/database/helpers/fn/dialects/sqlite.d.ts +9 -9
  15. package/dist/database/helpers/fn/dialects/sqlite.js +46 -16
  16. package/dist/database/helpers/fn/types.d.ts +12 -9
  17. package/dist/database/index.js +10 -19
  18. package/dist/database/migrations/20220429A-add-flows.d.ts +3 -0
  19. package/dist/database/migrations/20220429A-add-flows.js +83 -0
  20. package/dist/database/migrations/20220429B-add-color-to-insights-icon.d.ts +3 -0
  21. package/dist/database/migrations/20220429B-add-color-to-insights-icon.js +15 -0
  22. package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.d.ts +3 -0
  23. package/dist/database/migrations/20220429C-drop-non-null-from-ip-of-activity.js +15 -0
  24. package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.d.ts +3 -0
  25. package/dist/database/migrations/20220429D-drop-non-null-from-sender-of-notifications.js +15 -0
  26. package/dist/database/seeds/05-activity.yaml +0 -1
  27. package/dist/database/system-data/collections/collections.yaml +4 -0
  28. package/dist/database/system-data/fields/flows.yaml +21 -0
  29. package/dist/database/system-data/fields/operations.yaml +19 -0
  30. package/dist/database/system-data/fields/users.yaml +2 -4
  31. package/dist/database/system-data/relations/relations.yaml +20 -0
  32. package/dist/env.d.ts +1 -1
  33. package/dist/env.js +6 -30
  34. package/dist/extensions.d.ts +5 -1
  35. package/dist/extensions.js +96 -39
  36. package/dist/flows.d.ts +22 -0
  37. package/dist/flows.js +332 -0
  38. package/dist/messenger.d.ts +24 -0
  39. package/dist/messenger.js +64 -0
  40. package/dist/operations/condition/index.d.ts +6 -0
  41. package/dist/operations/condition/index.js +15 -0
  42. package/dist/operations/item-create/index.d.ts +8 -0
  43. package/dist/operations/item-create/index.js +40 -0
  44. package/dist/operations/item-delete/index.d.ts +9 -0
  45. package/dist/operations/item-delete/index.js +45 -0
  46. package/dist/operations/item-read/index.d.ts +9 -0
  47. package/dist/operations/item-read/index.js +45 -0
  48. package/dist/operations/item-update/index.d.ts +10 -0
  49. package/dist/operations/item-update/index.js +50 -0
  50. package/dist/operations/log/index.d.ts +5 -0
  51. package/dist/operations/log/index.js +14 -0
  52. package/dist/operations/mail/index.d.ts +7 -0
  53. package/dist/operations/mail/index.js +16 -0
  54. package/dist/operations/notification/index.d.ts +8 -0
  55. package/dist/operations/notification/index.js +39 -0
  56. package/dist/operations/request/index.d.ts +12 -0
  57. package/dist/operations/request/index.js +18 -0
  58. package/dist/operations/sleep/index.d.ts +5 -0
  59. package/dist/operations/sleep/index.js +9 -0
  60. package/dist/operations/transform/index.d.ts +5 -0
  61. package/dist/operations/transform/index.js +10 -0
  62. package/dist/operations/trigger/index.d.ts +6 -0
  63. package/dist/operations/trigger/index.js +21 -0
  64. package/dist/services/activity.d.ts +1 -2
  65. package/dist/services/activity.js +10 -10
  66. package/dist/services/authentication.d.ts +2 -2
  67. package/dist/services/authentication.js +7 -7
  68. package/dist/services/authorization.js +12 -0
  69. package/dist/services/flows.d.ts +12 -0
  70. package/dist/services/flows.js +47 -0
  71. package/dist/services/graphql.js +13 -2
  72. package/dist/services/import-export.js +7 -3
  73. package/dist/services/index.d.ts +2 -0
  74. package/dist/services/index.js +2 -0
  75. package/dist/services/items.js +1 -1
  76. package/dist/services/mail/index.js +2 -1
  77. package/dist/services/notifications.d.ts +2 -1
  78. package/dist/services/notifications.js +4 -3
  79. package/dist/services/operations.d.ts +12 -0
  80. package/dist/services/operations.js +47 -0
  81. package/dist/services/users.js +5 -0
  82. package/dist/services/webhooks.d.ts +2 -0
  83. package/dist/services/webhooks.js +8 -7
  84. package/dist/types/events.d.ts +18 -0
  85. package/dist/types/events.js +2 -0
  86. package/dist/types/index.d.ts +1 -1
  87. package/dist/types/index.js +1 -1
  88. package/dist/utils/apply-snapshot.js +3 -0
  89. package/dist/utils/construct-flow-tree.d.ts +2 -0
  90. package/dist/utils/construct-flow-tree.js +31 -0
  91. package/dist/utils/get-accountability-for-role.d.ts +7 -0
  92. package/dist/utils/get-accountability-for-role.js +36 -0
  93. package/dist/utils/get-column.js +1 -1
  94. package/dist/utils/job-queue.d.ts +9 -0
  95. package/dist/utils/job-queue.js +24 -0
  96. package/dist/utils/operation-options.d.ts +3 -0
  97. package/dist/utils/operation-options.js +45 -0
  98. package/dist/utils/validate-query.js +1 -1
  99. package/dist/webhooks.d.ts +2 -0
  100. package/dist/webhooks.js +17 -2
  101. package/package.json +19 -15
  102. package/dist/types/activity.d.ts +0 -9
  103. package/dist/types/activity.js +0 -13
  104. package/example.env +0 -202
package/dist/flows.js ADDED
@@ -0,0 +1,332 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.getFlowManager = void 0;
26
+ const sharedExceptions = __importStar(require("@directus/shared/exceptions"));
27
+ const types_1 = require("@directus/shared/types");
28
+ const micromustache_1 = require("micromustache");
29
+ const node_cron_1 = require("node-cron");
30
+ const database_1 = __importDefault(require("./database"));
31
+ const emitter_1 = __importDefault(require("./emitter"));
32
+ const env_1 = __importDefault(require("./env"));
33
+ const exceptions = __importStar(require("./exceptions"));
34
+ const logger_1 = __importDefault(require("./logger"));
35
+ const services = __importStar(require("./services"));
36
+ const services_1 = require("./services");
37
+ const construct_flow_tree_1 = require("./utils/construct-flow-tree");
38
+ const get_schema_1 = require("./utils/get-schema");
39
+ const activity_1 = require("./services/activity");
40
+ const revisions_1 = require("./services/revisions");
41
+ const lodash_1 = require("lodash");
42
+ const messenger_1 = require("./messenger");
43
+ const fast_redact_1 = __importDefault(require("fast-redact"));
44
+ const operation_options_1 = require("./utils/operation-options");
45
+ const job_queue_1 = require("./utils/job-queue");
46
+ let flowManager;
47
+ const redactLogs = (0, fast_redact_1.default)({
48
+ censor: '--redacted--',
49
+ paths: ['*.headers.authorization', '*.access_token', '*.headers.cookie'],
50
+ serialize: false,
51
+ });
52
+ function getFlowManager() {
53
+ if (flowManager) {
54
+ return flowManager;
55
+ }
56
+ flowManager = new FlowManager();
57
+ return flowManager;
58
+ }
59
+ exports.getFlowManager = getFlowManager;
60
+ const TRIGGER_KEY = '$trigger';
61
+ const ACCOUNTABILITY_KEY = '$accountability';
62
+ const LAST_KEY = '$last';
63
+ class FlowManager {
64
+ constructor() {
65
+ this.isLoaded = false;
66
+ this.operations = {};
67
+ this.triggerHandlers = [];
68
+ this.operationFlowHandlers = {};
69
+ this.webhookFlowHandlers = {};
70
+ this.reloadQueue = new job_queue_1.JobQueue();
71
+ const messenger = (0, messenger_1.getMessenger)();
72
+ messenger.subscribe('flows', (event) => {
73
+ if (event.type === 'reload') {
74
+ this.reloadQueue.enqueue(async () => {
75
+ if (this.isLoaded) {
76
+ await this.unload();
77
+ await this.load();
78
+ }
79
+ else {
80
+ logger_1.default.warn('Flows have to be loaded before they can be reloaded');
81
+ }
82
+ });
83
+ }
84
+ });
85
+ }
86
+ async initialize() {
87
+ if (!this.isLoaded) {
88
+ await this.load();
89
+ }
90
+ }
91
+ async reload() {
92
+ const messenger = (0, messenger_1.getMessenger)();
93
+ messenger.publish('flows', { type: 'reload' });
94
+ }
95
+ addOperation(id, operation) {
96
+ this.operations[id] = operation;
97
+ }
98
+ clearOperations() {
99
+ this.operations = {};
100
+ }
101
+ async runOperationFlow(id, data, context) {
102
+ if (!(id in this.operationFlowHandlers)) {
103
+ logger_1.default.warn(`Couldn't find operation triggered flow with id "${id}"`);
104
+ return null;
105
+ }
106
+ const handler = this.operationFlowHandlers[id];
107
+ return handler(data, context);
108
+ }
109
+ async runWebhookFlow(id, data, context) {
110
+ if (!(id in this.webhookFlowHandlers)) {
111
+ logger_1.default.warn(`Couldn't find webhook or manual triggered flow with id "${id}"`);
112
+ throw new exceptions.ForbiddenException();
113
+ }
114
+ const handler = this.webhookFlowHandlers[id];
115
+ return handler(data, context);
116
+ }
117
+ async load() {
118
+ var _a, _b, _c, _d, _e, _f, _g;
119
+ const flowsService = new services_1.FlowsService({ knex: (0, database_1.default)(), schema: await (0, get_schema_1.getSchema)() });
120
+ const flows = await flowsService.readByQuery({
121
+ filter: { status: { _eq: 'active' } },
122
+ fields: ['*', 'operations.*'],
123
+ });
124
+ const flowTrees = flows.map((flow) => (0, construct_flow_tree_1.constructFlowTree)(flow));
125
+ for (const flow of flowTrees) {
126
+ if (flow.trigger === 'event') {
127
+ const events = (_d = (_c = (_b = (_a = flow.options) === null || _a === void 0 ? void 0 : _a.scope) === null || _b === void 0 ? void 0 : _b.map((scope) => {
128
+ var _a, _b, _c;
129
+ if (['items.create', 'items.update', 'items.delete'].includes(scope)) {
130
+ return ((_c = (_b = (_a = flow.options) === null || _a === void 0 ? void 0 : _a.collections) === null || _b === void 0 ? void 0 : _b.map((collection) => {
131
+ if (collection.startsWith('directus_')) {
132
+ const action = scope.split('.')[1];
133
+ return collection.substring(9) + '.' + action;
134
+ }
135
+ return `${collection}.${scope}`;
136
+ })) !== null && _c !== void 0 ? _c : []);
137
+ }
138
+ return scope;
139
+ })) === null || _c === void 0 ? void 0 : _c.flat()) !== null && _d !== void 0 ? _d : [];
140
+ if (flow.options.type === 'filter') {
141
+ const handler = (payload, meta, context) => this.executeFlow(flow, { payload, ...meta }, {
142
+ accountability: context.accountability,
143
+ database: context.database,
144
+ getSchema: context.schema ? () => context.schema : get_schema_1.getSchema,
145
+ });
146
+ events.forEach((event) => emitter_1.default.onFilter(event, handler));
147
+ this.triggerHandlers.push({
148
+ id: flow.id,
149
+ events: events.map((event) => ({ type: 'filter', name: event, handler })),
150
+ });
151
+ }
152
+ else if (flow.options.type === 'action') {
153
+ const handler = (meta, context) => this.executeFlow(flow, meta, {
154
+ accountability: context.accountability,
155
+ database: context.database,
156
+ getSchema: context.schema ? () => context.schema : get_schema_1.getSchema,
157
+ });
158
+ events.forEach((event) => emitter_1.default.onAction(event, handler));
159
+ this.triggerHandlers.push({
160
+ id: flow.id,
161
+ events: events.map((event) => ({ type: 'action', name: event, handler })),
162
+ });
163
+ }
164
+ }
165
+ else if (flow.trigger === 'schedule') {
166
+ if ((0, node_cron_1.validate)(flow.options.cron)) {
167
+ const task = (0, node_cron_1.schedule)(flow.options.cron, async () => {
168
+ try {
169
+ await this.executeFlow(flow);
170
+ }
171
+ catch (error) {
172
+ logger_1.default.error(error);
173
+ }
174
+ });
175
+ this.triggerHandlers.push({ id: flow.id, events: [{ type: flow.trigger, task }] });
176
+ }
177
+ else {
178
+ logger_1.default.warn(`Couldn't register cron trigger. Provided cron is invalid: ${flow.options.cron}`);
179
+ }
180
+ }
181
+ else if (flow.trigger === 'operation') {
182
+ const handler = (data, context) => this.executeFlow(flow, data, context);
183
+ this.operationFlowHandlers[flow.id] = handler;
184
+ }
185
+ else if (flow.trigger === 'webhook') {
186
+ const handler = (data, context) => {
187
+ if (flow.options.async) {
188
+ this.executeFlow(flow, data, context);
189
+ }
190
+ else {
191
+ return this.executeFlow(flow, data, context);
192
+ }
193
+ };
194
+ const method = (_f = (_e = flow.options) === null || _e === void 0 ? void 0 : _e.method) !== null && _f !== void 0 ? _f : 'GET';
195
+ // Default return to $last for webhooks
196
+ flow.options.return = (_g = flow.options.return) !== null && _g !== void 0 ? _g : '$last';
197
+ this.webhookFlowHandlers[`${method}-${flow.id}`] = handler;
198
+ }
199
+ else if (flow.trigger === 'manual') {
200
+ const handler = (data, context) => {
201
+ var _a, _b, _c;
202
+ const enabledCollections = (_b = (_a = flow.options) === null || _a === void 0 ? void 0 : _a.collections) !== null && _b !== void 0 ? _b : [];
203
+ const targetCollection = (_c = data) === null || _c === void 0 ? void 0 : _c.body.collection;
204
+ if (!targetCollection) {
205
+ logger_1.default.warn(`Manual trigger requires "collection" to be specified in the payload`);
206
+ throw new exceptions.ForbiddenException();
207
+ }
208
+ if (enabledCollections.length === 0) {
209
+ logger_1.default.warn(`There is no collections configured for this manual trigger`);
210
+ throw new exceptions.ForbiddenException();
211
+ }
212
+ if (!enabledCollections.includes(targetCollection)) {
213
+ logger_1.default.warn(`Specified collection must be one of: ${enabledCollections.join(', ')}.`);
214
+ throw new exceptions.ForbiddenException();
215
+ }
216
+ if (flow.options.async) {
217
+ this.executeFlow(flow, data, context);
218
+ }
219
+ else {
220
+ return this.executeFlow(flow, data, context);
221
+ }
222
+ };
223
+ // Default return to $last for manual
224
+ flow.options.return = '$last';
225
+ this.webhookFlowHandlers[`POST-${flow.id}`] = handler;
226
+ }
227
+ }
228
+ this.isLoaded = true;
229
+ }
230
+ async unload() {
231
+ for (const trigger of this.triggerHandlers) {
232
+ trigger.events.forEach((event) => {
233
+ switch (event.type) {
234
+ case 'filter':
235
+ emitter_1.default.offFilter(event.name, event.handler);
236
+ break;
237
+ case 'action':
238
+ emitter_1.default.offAction(event.name, event.handler);
239
+ break;
240
+ case 'schedule':
241
+ event.task.stop();
242
+ break;
243
+ }
244
+ });
245
+ }
246
+ this.triggerHandlers = [];
247
+ this.operationFlowHandlers = {};
248
+ this.webhookFlowHandlers = {};
249
+ this.isLoaded = false;
250
+ }
251
+ async executeFlow(flow, data = null, context = {}) {
252
+ var _a, _b, _c, _d, _e, _f;
253
+ const database = (_a = context.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
254
+ const schema = (_b = context.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database }));
255
+ const keyedData = {
256
+ [TRIGGER_KEY]: data,
257
+ [LAST_KEY]: data,
258
+ [ACCOUNTABILITY_KEY]: (_c = context === null || context === void 0 ? void 0 : context.accountability) !== null && _c !== void 0 ? _c : null,
259
+ };
260
+ let nextOperation = flow.operation;
261
+ const steps = [];
262
+ while (nextOperation !== null) {
263
+ const { successor, data, status, options } = await this.executeOperation(nextOperation, keyedData, context);
264
+ keyedData[nextOperation.key] = data;
265
+ keyedData[LAST_KEY] = data;
266
+ steps.push({ operation: nextOperation.id, key: nextOperation.key, status, options });
267
+ nextOperation = successor;
268
+ }
269
+ if (flow.accountability !== null) {
270
+ const activityService = new activity_1.ActivityService({
271
+ knex: database,
272
+ schema: schema,
273
+ });
274
+ const accountability = context === null || context === void 0 ? void 0 : context.accountability;
275
+ const activity = await activityService.createOne({
276
+ action: types_1.Action.RUN,
277
+ user: (_d = accountability === null || accountability === void 0 ? void 0 : accountability.user) !== null && _d !== void 0 ? _d : null,
278
+ collection: 'directus_flows',
279
+ ip: (_e = accountability === null || accountability === void 0 ? void 0 : accountability.ip) !== null && _e !== void 0 ? _e : null,
280
+ user_agent: (_f = accountability === null || accountability === void 0 ? void 0 : accountability.userAgent) !== null && _f !== void 0 ? _f : null,
281
+ item: flow.id,
282
+ });
283
+ if (flow.accountability === 'all') {
284
+ const revisionsService = new revisions_1.RevisionsService({
285
+ knex: database,
286
+ schema: schema,
287
+ });
288
+ await revisionsService.createOne({
289
+ activity: activity,
290
+ collection: 'directus_flows',
291
+ item: flow.id,
292
+ data: {
293
+ steps: steps,
294
+ data: redactLogs((0, lodash_1.omit)(keyedData, '$accountability.permissions')), // Permissions is a ton of data, and is just a copy of what's in the directus_permissions table
295
+ },
296
+ });
297
+ }
298
+ }
299
+ if (flow.options.return === '$all') {
300
+ return keyedData;
301
+ }
302
+ else if (flow.options.return) {
303
+ return (0, micromustache_1.get)(keyedData, flow.options.return);
304
+ }
305
+ return undefined;
306
+ }
307
+ async executeOperation(operation, keyedData, context = {}) {
308
+ if (!(operation.type in this.operations)) {
309
+ logger_1.default.warn(`Couldn't find operation ${operation.type}`);
310
+ return { successor: null, status: 'unknown', data: null, options: null };
311
+ }
312
+ const handler = this.operations[operation.type];
313
+ const options = (0, operation_options_1.applyOperationOptions)(operation.options, keyedData);
314
+ try {
315
+ const result = await handler(options, {
316
+ services,
317
+ exceptions: { ...exceptions, ...sharedExceptions },
318
+ env: env_1.default,
319
+ database: (0, database_1.default)(),
320
+ logger: logger_1.default,
321
+ getSchema: get_schema_1.getSchema,
322
+ data: keyedData,
323
+ accountability: null,
324
+ ...context,
325
+ });
326
+ return { successor: operation.resolve, status: 'resolve', data: result !== null && result !== void 0 ? result : null, options };
327
+ }
328
+ catch (error) {
329
+ return { successor: operation.reject, status: 'reject', data: error !== null && error !== void 0 ? error : null, options };
330
+ }
331
+ }
332
+ }
@@ -0,0 +1,24 @@
1
+ import IORedis from 'ioredis';
2
+ export declare type MessengerSubscriptionCallback = (payload: Record<string, any>) => void;
3
+ export interface Messenger {
4
+ publish: (channel: string, payload: Record<string, any>) => void;
5
+ subscribe: (channel: string, callback: MessengerSubscriptionCallback) => void;
6
+ unsubscribe: (channel: string) => void;
7
+ }
8
+ export declare class MessengerMemory implements Messenger {
9
+ handlers: Record<string, MessengerSubscriptionCallback>;
10
+ constructor();
11
+ publish(channel: string, payload: Record<string, any>): void;
12
+ subscribe(channel: string, callback: MessengerSubscriptionCallback): void;
13
+ unsubscribe(channel: string): void;
14
+ }
15
+ export declare class MessengerRedis implements Messenger {
16
+ namespace: string;
17
+ pub: IORedis.Redis;
18
+ sub: IORedis.Redis;
19
+ constructor();
20
+ publish(channel: string, payload: Record<string, any>): void;
21
+ subscribe(channel: string, callback: MessengerSubscriptionCallback): void;
22
+ unsubscribe(channel: string): void;
23
+ }
24
+ export declare function getMessenger(): Messenger;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getMessenger = exports.MessengerRedis = exports.MessengerMemory = void 0;
7
+ const ioredis_1 = __importDefault(require("ioredis"));
8
+ const env_1 = __importDefault(require("./env"));
9
+ const get_config_from_env_1 = require("./utils/get-config-from-env");
10
+ const parse_json_1 = require("./utils/parse-json");
11
+ class MessengerMemory {
12
+ constructor() {
13
+ this.handlers = {};
14
+ }
15
+ publish(channel, payload) {
16
+ var _a, _b;
17
+ (_b = (_a = this.handlers)[channel]) === null || _b === void 0 ? void 0 : _b.call(_a, payload);
18
+ }
19
+ subscribe(channel, callback) {
20
+ this.handlers[channel] = callback;
21
+ }
22
+ unsubscribe(channel) {
23
+ delete this.handlers[channel];
24
+ }
25
+ }
26
+ exports.MessengerMemory = MessengerMemory;
27
+ class MessengerRedis {
28
+ constructor() {
29
+ var _a, _b, _c;
30
+ const config = (0, get_config_from_env_1.getConfigFromEnv)('MESSENGER_REDIS');
31
+ this.pub = new ioredis_1.default((_a = env_1.default.MESSENGER_REDIS) !== null && _a !== void 0 ? _a : config);
32
+ this.sub = new ioredis_1.default((_b = env_1.default.MESSENGER_REDIS) !== null && _b !== void 0 ? _b : config);
33
+ this.namespace = (_c = env_1.default.MESSENGER_NAMESPACE) !== null && _c !== void 0 ? _c : 'directus';
34
+ }
35
+ publish(channel, payload) {
36
+ this.pub.publish(`${this.namespace}:${channel}`, JSON.stringify(payload));
37
+ }
38
+ subscribe(channel, callback) {
39
+ this.sub.subscribe(`${this.namespace}:${channel}`);
40
+ this.sub.on('message', (messageChannel, payloadString) => {
41
+ const payload = (0, parse_json_1.parseJSON)(payloadString);
42
+ if (messageChannel === `${this.namespace}:${channel}`) {
43
+ callback(payload);
44
+ }
45
+ });
46
+ }
47
+ unsubscribe(channel) {
48
+ this.sub.unsubscribe(`${this.namespace}:${channel}`);
49
+ }
50
+ }
51
+ exports.MessengerRedis = MessengerRedis;
52
+ let messenger;
53
+ function getMessenger() {
54
+ if (messenger)
55
+ return messenger;
56
+ if (env_1.default.MESSENGER_STORE === 'redis') {
57
+ messenger = new MessengerRedis();
58
+ }
59
+ else {
60
+ messenger = new MessengerMemory();
61
+ }
62
+ return messenger;
63
+ }
64
+ exports.getMessenger = getMessenger;
@@ -0,0 +1,6 @@
1
+ import { Filter } from '@directus/shared/types';
2
+ declare type Options = {
3
+ filter: Filter;
4
+ };
5
+ declare const _default: import("@directus/shared/types").OperationApiConfig<Options>;
6
+ export default _default;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@directus/shared/utils");
4
+ exports.default = (0, utils_1.defineOperationApi)({
5
+ id: 'condition',
6
+ handler: ({ filter }, { data }) => {
7
+ const errors = (0, utils_1.validatePayload)(filter, data);
8
+ if (errors.length > 0) {
9
+ throw errors;
10
+ }
11
+ else {
12
+ return null;
13
+ }
14
+ },
15
+ });
@@ -0,0 +1,8 @@
1
+ declare type Options = {
2
+ collection: string;
3
+ payload?: Record<string, any> | string | null;
4
+ emitEvents: boolean;
5
+ permissions: string;
6
+ };
7
+ declare const _default: import("@directus/shared/types").OperationApiConfig<Options>;
8
+ export default _default;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@directus/shared/utils");
4
+ const services_1 = require("../../services");
5
+ const operation_options_1 = require("../../utils/operation-options");
6
+ const get_accountability_for_role_1 = require("../../utils/get-accountability-for-role");
7
+ exports.default = (0, utils_1.defineOperationApi)({
8
+ id: 'item-create',
9
+ handler: async ({ collection, payload, emitEvents, permissions }, { accountability, database, getSchema }) => {
10
+ var _a;
11
+ const schema = await getSchema({ database });
12
+ let customAccountability;
13
+ if (!permissions || permissions === '$trigger') {
14
+ customAccountability = accountability;
15
+ }
16
+ else if (permissions === '$full') {
17
+ customAccountability = null;
18
+ }
19
+ else if (permissions === '$public') {
20
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(null, { database, schema, accountability });
21
+ }
22
+ else {
23
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(permissions, { database, schema, accountability });
24
+ }
25
+ const itemsService = new services_1.ItemsService(collection, {
26
+ schema: await getSchema({ database }),
27
+ accountability: customAccountability,
28
+ knex: database,
29
+ });
30
+ const payloadObject = (_a = (0, operation_options_1.optionToObject)(payload)) !== null && _a !== void 0 ? _a : null;
31
+ let result;
32
+ if (!payloadObject) {
33
+ result = null;
34
+ }
35
+ else {
36
+ result = await itemsService.createMany((0, utils_1.toArray)(payloadObject), { emitEvents });
37
+ }
38
+ return result;
39
+ },
40
+ });
@@ -0,0 +1,9 @@
1
+ import { PrimaryKey } from '@directus/shared/types';
2
+ declare type Options = {
3
+ collection: string;
4
+ key?: PrimaryKey | PrimaryKey[] | null;
5
+ query?: Record<string, any> | string | null;
6
+ permissions: string;
7
+ };
8
+ declare const _default: import("@directus/shared/types").OperationApiConfig<Options>;
9
+ export default _default;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@directus/shared/utils");
4
+ const services_1 = require("../../services");
5
+ const operation_options_1 = require("../../utils/operation-options");
6
+ const get_accountability_for_role_1 = require("../../utils/get-accountability-for-role");
7
+ exports.default = (0, utils_1.defineOperationApi)({
8
+ id: 'item-delete',
9
+ handler: async ({ collection, key, query, permissions }, { accountability, database, getSchema }) => {
10
+ const schema = await getSchema({ database });
11
+ let customAccountability;
12
+ if (!permissions || permissions === '$trigger') {
13
+ customAccountability = accountability;
14
+ }
15
+ else if (permissions === '$full') {
16
+ customAccountability = null;
17
+ }
18
+ else if (permissions === '$public') {
19
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(null, { database, schema, accountability });
20
+ }
21
+ else {
22
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(permissions, { database, schema, accountability });
23
+ }
24
+ const itemsService = new services_1.ItemsService(collection, {
25
+ schema: await getSchema({ database }),
26
+ accountability: customAccountability,
27
+ knex: database,
28
+ });
29
+ const queryObject = query ? (0, operation_options_1.optionToObject)(query) : {};
30
+ let result;
31
+ if (!key) {
32
+ result = await itemsService.deleteByQuery(queryObject);
33
+ }
34
+ else {
35
+ const keys = (0, utils_1.toArray)(key);
36
+ if (keys.length === 1) {
37
+ result = await itemsService.deleteOne(keys[0]);
38
+ }
39
+ else {
40
+ result = await itemsService.deleteMany(keys);
41
+ }
42
+ }
43
+ return result;
44
+ },
45
+ });
@@ -0,0 +1,9 @@
1
+ import { PrimaryKey } from '@directus/shared/types';
2
+ declare type Options = {
3
+ collection: string;
4
+ key?: PrimaryKey | PrimaryKey[] | null;
5
+ query?: Record<string, any> | string | null;
6
+ permissions: string;
7
+ };
8
+ declare const _default: import("@directus/shared/types").OperationApiConfig<Options>;
9
+ export default _default;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@directus/shared/utils");
4
+ const services_1 = require("../../services");
5
+ const operation_options_1 = require("../../utils/operation-options");
6
+ const get_accountability_for_role_1 = require("../../utils/get-accountability-for-role");
7
+ exports.default = (0, utils_1.defineOperationApi)({
8
+ id: 'item-read',
9
+ handler: async ({ collection, key, query, permissions }, { accountability, database, getSchema }) => {
10
+ const schema = await getSchema({ database });
11
+ let customAccountability;
12
+ if (!permissions || permissions === '$trigger') {
13
+ customAccountability = accountability;
14
+ }
15
+ else if (permissions === '$full') {
16
+ customAccountability = null;
17
+ }
18
+ else if (permissions === '$public') {
19
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(null, { database, schema, accountability });
20
+ }
21
+ else {
22
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(permissions, { database, schema, accountability });
23
+ }
24
+ const itemsService = new services_1.ItemsService(collection, {
25
+ schema,
26
+ accountability: customAccountability,
27
+ knex: database,
28
+ });
29
+ const queryObject = query ? (0, operation_options_1.optionToObject)(query) : {};
30
+ let result;
31
+ if (!key) {
32
+ result = await itemsService.readByQuery(queryObject);
33
+ }
34
+ else {
35
+ const keys = (0, utils_1.toArray)(key);
36
+ if (keys.length === 1) {
37
+ result = await itemsService.readOne(keys[0], queryObject);
38
+ }
39
+ else {
40
+ result = await itemsService.readMany(keys, queryObject);
41
+ }
42
+ }
43
+ return result;
44
+ },
45
+ });
@@ -0,0 +1,10 @@
1
+ import { PrimaryKey } from '@directus/shared/types';
2
+ declare type Options = {
3
+ collection: string;
4
+ key?: PrimaryKey | PrimaryKey[] | null;
5
+ payload?: Record<string, any> | string | null;
6
+ query?: Record<string, any> | string | null;
7
+ permissions: string;
8
+ };
9
+ declare const _default: import("@directus/shared/types").OperationApiConfig<Options>;
10
+ export default _default;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@directus/shared/utils");
4
+ const services_1 = require("../../services");
5
+ const operation_options_1 = require("../../utils/operation-options");
6
+ const get_accountability_for_role_1 = require("../../utils/get-accountability-for-role");
7
+ exports.default = (0, utils_1.defineOperationApi)({
8
+ id: 'item-update',
9
+ handler: async ({ collection, key, payload, query, permissions }, { accountability, database, getSchema }) => {
10
+ var _a;
11
+ const schema = await getSchema({ database });
12
+ let customAccountability;
13
+ if (!permissions || permissions === '$trigger') {
14
+ customAccountability = accountability;
15
+ }
16
+ else if (permissions === '$full') {
17
+ customAccountability = null;
18
+ }
19
+ else if (permissions === '$public') {
20
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(null, { database, schema, accountability });
21
+ }
22
+ else {
23
+ customAccountability = await (0, get_accountability_for_role_1.getAccountabilityForRole)(permissions, { database, schema, accountability });
24
+ }
25
+ const itemsService = new services_1.ItemsService(collection, {
26
+ schema: await getSchema({ database }),
27
+ accountability: customAccountability,
28
+ knex: database,
29
+ });
30
+ const payloadObject = (_a = (0, operation_options_1.optionToObject)(payload)) !== null && _a !== void 0 ? _a : null;
31
+ const queryObject = query ? (0, operation_options_1.optionToObject)(query) : {};
32
+ if (!payloadObject) {
33
+ return null;
34
+ }
35
+ let result;
36
+ if (!key) {
37
+ result = await itemsService.updateByQuery(queryObject, payloadObject);
38
+ }
39
+ else {
40
+ const keys = (0, utils_1.toArray)(key);
41
+ if (keys.length === 1) {
42
+ result = await itemsService.updateOne(keys[0], payloadObject);
43
+ }
44
+ else {
45
+ result = await itemsService.updateMany(keys, payloadObject);
46
+ }
47
+ }
48
+ return result;
49
+ },
50
+ });