directus 9.12.0 → 9.13.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.
- package/dist/app.js +11 -1
- package/dist/auth/drivers/index.js +5 -1
- package/dist/auth/drivers/ldap.js +5 -1
- package/dist/auth/drivers/oauth2.js +15 -23
- package/dist/auth/drivers/openid.js +16 -24
- package/dist/cli/commands/bootstrap/index.js +5 -1
- package/dist/cli/commands/schema/apply.js +7 -3
- package/dist/cli/commands/schema/snapshot.d.ts +1 -1
- package/dist/cli/commands/schema/snapshot.js +33 -25
- package/dist/cli/index.js +1 -1
- package/dist/cli/utils/create-env/env-stub.liquid +11 -11
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +5 -1
- package/dist/controllers/assets.js +5 -5
- package/dist/controllers/dashboards.js +4 -1
- package/dist/controllers/files.js +8 -5
- package/dist/controllers/flows.js +4 -1
- package/dist/controllers/folders.js +4 -1
- package/dist/controllers/items.js +4 -1
- package/dist/controllers/notifications.js +4 -1
- package/dist/controllers/operations.js +4 -1
- package/dist/controllers/panels.js +4 -1
- package/dist/controllers/permissions.js +4 -1
- package/dist/controllers/presets.js +4 -1
- package/dist/controllers/roles.js +4 -1
- package/dist/controllers/shares.js +4 -1
- package/dist/controllers/users.js +75 -3
- package/dist/controllers/utils.js +3 -3
- package/dist/database/helpers/date/dialects/sqlite.js +3 -0
- package/dist/database/helpers/fn/dialects/oracle.d.ts +9 -9
- package/dist/database/helpers/fn/dialects/oracle.js +22 -16
- package/dist/database/helpers/fn/dialects/sqlite.d.ts +9 -9
- package/dist/database/helpers/fn/dialects/sqlite.js +46 -16
- package/dist/database/helpers/fn/types.d.ts +12 -9
- package/dist/database/helpers/index.js +5 -1
- package/dist/database/index.js +2 -0
- package/dist/database/migrations/20210225A-add-relations-sort-field.js +2 -2
- package/dist/database/migrations/20210506A-rename-interfaces.js +2 -2
- package/dist/database/migrations/20210802A-replace-groups.js +2 -2
- package/dist/database/migrations/20210805A-update-groups.js +2 -2
- package/dist/database/migrations/20210805B-change-image-metadata-structure.js +3 -3
- package/dist/database/migrations/20211007A-update-presets.js +5 -5
- package/dist/database/migrations/20220429A-add-flows.js +1 -2
- package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.d.ts +3 -0
- package/dist/database/migrations/20220614A-rename-hook-trigger-to-event.js +11 -0
- package/dist/database/system-data/fields/dashboards.yaml +1 -0
- package/dist/database/system-data/fields/flows.yaml +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/env.js +8 -3
- package/dist/exceptions/database/translate.js +5 -1
- package/dist/exceptions/index.js +5 -1
- package/dist/extensions.d.ts +2 -1
- package/dist/extensions.js +31 -23
- package/dist/flows.d.ts +5 -0
- package/dist/flows.js +66 -40
- package/dist/index.js +5 -1
- package/dist/logger.js +5 -1
- package/dist/messenger.js +2 -2
- package/dist/middleware/graphql.js +2 -2
- package/dist/middleware/respond.js +10 -1
- package/dist/middleware/validate-batch.js +3 -1
- package/dist/operations/item-create/index.js +1 -2
- package/dist/operations/item-delete/index.d.ts +1 -0
- package/dist/operations/item-delete/index.js +8 -7
- package/dist/operations/item-read/index.js +7 -6
- package/dist/operations/item-update/index.d.ts +1 -0
- package/dist/operations/item-update/index.js +9 -8
- package/dist/operations/log/index.js +1 -2
- package/dist/operations/notification/index.js +1 -2
- package/dist/operations/request/index.d.ts +4 -1
- package/dist/operations/request/index.js +5 -1
- package/dist/operations/transform/index.js +1 -2
- package/dist/operations/trigger/index.js +1 -2
- package/dist/server.js +5 -1
- package/dist/services/assets.js +5 -1
- package/dist/services/collections.js +5 -1
- package/dist/services/fields.d.ts +3 -3
- package/dist/services/fields.js +25 -17
- package/dist/services/files.js +5 -1
- package/dist/services/flows.d.ts +1 -2
- package/dist/services/flows.js +19 -8
- package/dist/services/{graphql.d.ts → graphql/index.d.ts} +3 -5
- package/dist/services/{graphql.js → graphql/index.js} +115 -102
- package/dist/services/graphql/types/date.d.ts +2 -0
- package/dist/services/graphql/types/date.js +9 -0
- package/dist/services/graphql/types/geojson.d.ts +2 -0
- package/dist/services/graphql/types/geojson.js +10 -0
- package/dist/services/graphql/types/string-or-float.d.ts +5 -0
- package/dist/services/graphql/types/string-or-float.js +34 -0
- package/dist/services/graphql/types/void.d.ts +2 -0
- package/dist/services/graphql/types/void.js +17 -0
- package/dist/services/graphql/utils/add-path-to-validation-error.d.ts +2 -0
- package/dist/services/graphql/utils/add-path-to-validation-error.js +20 -0
- package/dist/services/import-export.js +13 -10
- package/dist/services/index.js +5 -1
- package/dist/services/items.d.ts +5 -1
- package/dist/services/items.js +22 -2
- package/dist/services/mail/index.js +8 -6
- package/dist/services/operations.d.ts +1 -2
- package/dist/services/operations.js +19 -8
- package/dist/services/payload.js +2 -3
- package/dist/services/permissions.d.ts +1 -0
- package/dist/services/permissions.js +5 -0
- package/dist/services/relations.js +5 -1
- package/dist/services/roles.d.ts +1 -0
- package/dist/services/roles.js +9 -0
- package/dist/services/server.js +5 -1
- package/dist/services/users.d.ts +1 -0
- package/dist/services/users.js +22 -0
- package/dist/types/index.js +5 -1
- package/dist/utils/apply-query.js +24 -15
- package/dist/utils/apply-snapshot.js +3 -0
- package/dist/utils/calculate-field-depth.d.ts +33 -0
- package/dist/utils/calculate-field-depth.js +75 -0
- package/dist/utils/get-column.js +1 -1
- package/dist/utils/get-default-value.js +3 -13
- package/dist/utils/get-graphql-type.js +4 -3
- package/dist/utils/get-local-type.d.ts +6 -3
- package/dist/utils/get-permissions.js +3 -4
- package/dist/utils/get-schema.js +1 -2
- package/dist/utils/get-string-byte-size.d.ts +4 -0
- package/dist/utils/get-string-byte-size.js +10 -0
- package/dist/utils/job-queue.d.ts +9 -0
- package/dist/utils/job-queue.js +24 -0
- package/dist/utils/jwt.js +5 -1
- package/dist/utils/sanitize-query.js +4 -5
- package/dist/utils/validate-query.js +50 -0
- package/dist/webhooks.js +5 -1
- package/package.json +75 -74
- package/dist/utils/operation-options.d.ts +0 -3
- package/dist/utils/operation-options.js +0 -45
- package/dist/utils/parse-json.d.ts +0 -5
- package/dist/utils/parse-json.js +0 -19
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.down = exports.up = void 0;
|
|
4
|
-
const
|
|
4
|
+
const utils_1 = require("@directus/shared/utils");
|
|
5
5
|
// Change image metadata structure to match the output from 'exifr'
|
|
6
6
|
async function up(knex) {
|
|
7
7
|
const files = await knex
|
|
@@ -11,7 +11,7 @@ async function up(knex) {
|
|
|
11
11
|
for (const { id, metadata } of files) {
|
|
12
12
|
let prevMetadata;
|
|
13
13
|
try {
|
|
14
|
-
prevMetadata = (0,
|
|
14
|
+
prevMetadata = (0, utils_1.parseJSON)(metadata);
|
|
15
15
|
}
|
|
16
16
|
catch {
|
|
17
17
|
continue;
|
|
@@ -55,7 +55,7 @@ async function down(knex) {
|
|
|
55
55
|
.whereNotNull('metadata')
|
|
56
56
|
.whereNot('metadata', '{}');
|
|
57
57
|
for (const { id, metadata } of files) {
|
|
58
|
-
const prevMetadata = (0,
|
|
58
|
+
const prevMetadata = (0, utils_1.parseJSON)(metadata);
|
|
59
59
|
// Update only required if metadata has keys other than 'icc' and 'iptc'
|
|
60
60
|
if (Object.keys(prevMetadata).filter((key) => key !== 'icc' && key !== 'iptc').length > 0) {
|
|
61
61
|
// Put all data under 'exif' and rename/move keys afterwards
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.down = exports.up = void 0;
|
|
4
|
+
const utils_1 = require("@directus/shared/utils");
|
|
4
5
|
const nanoid_1 = require("nanoid");
|
|
5
|
-
const parse_json_1 = require("../../utils/parse-json");
|
|
6
6
|
async function up(knex) {
|
|
7
7
|
var _a;
|
|
8
8
|
await knex.schema.alterTable('directus_presets', (table) => {
|
|
@@ -13,7 +13,7 @@ async function up(knex) {
|
|
|
13
13
|
.from('directus_presets');
|
|
14
14
|
for (const preset of presets) {
|
|
15
15
|
if (preset.filters) {
|
|
16
|
-
const oldFilters = (_a = (typeof preset.filters === 'string' ? (0,
|
|
16
|
+
const oldFilters = (_a = (typeof preset.filters === 'string' ? (0, utils_1.parseJSON)(preset.filters) : preset.filters)) !== null && _a !== void 0 ? _a : [];
|
|
17
17
|
if (oldFilters.length === 0)
|
|
18
18
|
continue;
|
|
19
19
|
const newFilter = {
|
|
@@ -35,7 +35,7 @@ async function up(knex) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
if (preset.layout_query) {
|
|
38
|
-
const layoutQuery = typeof preset.layout_query === 'string' ? (0,
|
|
38
|
+
const layoutQuery = typeof preset.layout_query === 'string' ? (0, utils_1.parseJSON)(preset.layout_query) : preset.layout_query;
|
|
39
39
|
for (const [layout, query] of Object.entries(layoutQuery)) {
|
|
40
40
|
if (query.sort) {
|
|
41
41
|
query.sort = [query.sort];
|
|
@@ -62,7 +62,7 @@ async function down(knex) {
|
|
|
62
62
|
.from('directus_presets');
|
|
63
63
|
for (const preset of presets) {
|
|
64
64
|
if (preset.filter) {
|
|
65
|
-
const newFilter = (_a = (typeof preset.filter === 'string' ? (0,
|
|
65
|
+
const newFilter = (_a = (typeof preset.filter === 'string' ? (0, utils_1.parseJSON)(preset.filter) : preset.filter)) !== null && _a !== void 0 ? _a : {};
|
|
66
66
|
if (Object.keys(newFilter).length === 0)
|
|
67
67
|
continue;
|
|
68
68
|
const oldFilters = [];
|
|
@@ -86,7 +86,7 @@ async function down(knex) {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
if (preset.layout_query) {
|
|
89
|
-
const layoutQuery = typeof preset.layout_query === 'string' ? (0,
|
|
89
|
+
const layoutQuery = typeof preset.layout_query === 'string' ? (0, utils_1.parseJSON)(preset.layout_query) : preset.layout_query;
|
|
90
90
|
for (const [layout, query] of Object.entries(layoutQuery)) {
|
|
91
91
|
if (query.sort && Array.isArray(query.sort)) {
|
|
92
92
|
query.sort = (_l = (_k = query.sort) === null || _k === void 0 ? void 0 : _k[0]) !== null && _l !== void 0 ? _l : null;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.down = exports.up = void 0;
|
|
4
4
|
const utils_1 = require("@directus/shared/utils");
|
|
5
5
|
const uuid_1 = require("uuid");
|
|
6
|
-
const parse_json_1 = require("../../utils/parse-json");
|
|
7
6
|
async function up(knex) {
|
|
8
7
|
await knex.schema.createTable('directus_flows', (table) => {
|
|
9
8
|
table.uuid('id').primary().notNullable();
|
|
@@ -59,7 +58,7 @@ async function up(knex) {
|
|
|
59
58
|
position_y: 1,
|
|
60
59
|
options: JSON.stringify({
|
|
61
60
|
url: webhook.url,
|
|
62
|
-
headers: typeof webhook.headers === 'string' ? (0,
|
|
61
|
+
headers: typeof webhook.headers === 'string' ? (0, utils_1.parseJSON)(webhook.headers) : webhook.headers,
|
|
63
62
|
data: webhook.data ? '{{$trigger}}' : null,
|
|
64
63
|
method: webhook.method,
|
|
65
64
|
}),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.down = exports.up = void 0;
|
|
4
|
+
async function up(knex) {
|
|
5
|
+
await knex('directus_flows').update({ trigger: 'event' }).where('trigger', '=', 'hook');
|
|
6
|
+
}
|
|
7
|
+
exports.up = up;
|
|
8
|
+
async function down(knex) {
|
|
9
|
+
await knex('directus_flows').update({ trigger: 'hook' }).where('trigger', '=', 'event');
|
|
10
|
+
}
|
|
11
|
+
exports.down = down;
|
package/dist/env.d.ts
CHANGED
package/dist/env.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* @NOTE
|
|
4
|
-
* For all possible keys, see: https://docs.directus.io/
|
|
4
|
+
* For all possible keys, see: https://docs.directus.io/self-hosted/config-options/
|
|
5
5
|
*/
|
|
6
6
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -14,7 +14,7 @@ const lodash_1 = require("lodash");
|
|
|
14
14
|
const path_1 = __importDefault(require("path"));
|
|
15
15
|
const require_yaml_1 = require("./utils/require-yaml");
|
|
16
16
|
const utils_1 = require("@directus/shared/utils");
|
|
17
|
-
const
|
|
17
|
+
const utils_2 = require("@directus/shared/utils");
|
|
18
18
|
// keeping this here for now to prevent a circular import to constants.ts
|
|
19
19
|
const allowedEnvironmentVars = [
|
|
20
20
|
// general
|
|
@@ -78,6 +78,7 @@ const allowedEnvironmentVars = [
|
|
|
78
78
|
'CACHE_REDIS_PORT',
|
|
79
79
|
'CACHE_REDIS_PASSWORD',
|
|
80
80
|
'CACHE_MEMCACHE',
|
|
81
|
+
'CACHE_VALUE_MAX_SIZE',
|
|
81
82
|
// storage
|
|
82
83
|
'STORAGE_LOCATIONS',
|
|
83
84
|
'STORAGE_.+_DRIVER',
|
|
@@ -140,6 +141,7 @@ const allowedEnvironmentVars = [
|
|
|
140
141
|
// emails
|
|
141
142
|
'EMAIL_FROM',
|
|
142
143
|
'EMAIL_TRANSPORT',
|
|
144
|
+
'EMAIL_VERIFY_SETUP',
|
|
143
145
|
'EMAIL_SENDMAIL_NEW_LINE',
|
|
144
146
|
'EMAIL_SENDMAIL_PATH',
|
|
145
147
|
'EMAIL_SMTP_HOST',
|
|
@@ -171,6 +173,7 @@ const defaults = {
|
|
|
171
173
|
PORT: 8055,
|
|
172
174
|
PUBLIC_URL: '/',
|
|
173
175
|
MAX_PAYLOAD_SIZE: '100kb',
|
|
176
|
+
MAX_RELATIONAL_DEPTH: 10,
|
|
174
177
|
DB_EXCLUDE_TABLES: 'spatial_ref_sys,sysdiagrams',
|
|
175
178
|
STORAGE_LOCATIONS: 'local',
|
|
176
179
|
STORAGE_LOCAL_DRIVER: 'local',
|
|
@@ -200,11 +203,13 @@ const defaults = {
|
|
|
200
203
|
CACHE_CONTROL_S_MAXAGE: '0',
|
|
201
204
|
CACHE_SCHEMA: true,
|
|
202
205
|
CACHE_PERMISSIONS: true,
|
|
206
|
+
CACHE_VALUE_MAX_SIZE: false,
|
|
203
207
|
AUTH_PROVIDERS: '',
|
|
204
208
|
AUTH_DISABLE_DEFAULT: false,
|
|
205
209
|
EXTENSIONS_PATH: './extensions',
|
|
206
210
|
EXTENSIONS_AUTO_RELOAD: false,
|
|
207
211
|
EMAIL_FROM: 'no-reply@directus.io',
|
|
212
|
+
EMAIL_VERIFY_SETUP: true,
|
|
208
213
|
EMAIL_TRANSPORT: 'sendmail',
|
|
209
214
|
EMAIL_SENDMAIL_NEW_LINE: 'unix',
|
|
210
215
|
EMAIL_SENDMAIL_PATH: '/usr/sbin/sendmail',
|
|
@@ -407,7 +412,7 @@ function processValues(env) {
|
|
|
407
412
|
}
|
|
408
413
|
function tryJSON(value) {
|
|
409
414
|
try {
|
|
410
|
-
return (0,
|
|
415
|
+
return (0, utils_2.parseJSON)(value);
|
|
411
416
|
}
|
|
412
417
|
catch {
|
|
413
418
|
return value;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/exceptions/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/extensions.d.ts
CHANGED
|
@@ -13,10 +13,11 @@ declare class ExtensionManager {
|
|
|
13
13
|
private apiExtensions;
|
|
14
14
|
private apiEmitter;
|
|
15
15
|
private endpointRouter;
|
|
16
|
+
private reloadQueue;
|
|
16
17
|
private watcher;
|
|
17
18
|
constructor();
|
|
18
19
|
initialize(options?: Partial<Options>): Promise<void>;
|
|
19
|
-
reload():
|
|
20
|
+
reload(): void;
|
|
20
21
|
getExtensionsList(type?: ExtensionType): string[];
|
|
21
22
|
getAppExtensions(type: AppExtensionType): string | undefined;
|
|
22
23
|
getEndpointRouter(): Router;
|
package/dist/extensions.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -47,6 +51,7 @@ const chokidar_1 = __importDefault(require("chokidar"));
|
|
|
47
51
|
const utils_1 = require("@directus/shared/utils");
|
|
48
52
|
const flows_1 = require("./flows");
|
|
49
53
|
const globby_1 = __importDefault(require("globby"));
|
|
54
|
+
const job_queue_1 = require("./utils/job-queue");
|
|
50
55
|
let extensionManager;
|
|
51
56
|
function getExtensionManager() {
|
|
52
57
|
if (extensionManager) {
|
|
@@ -70,6 +75,7 @@ class ExtensionManager {
|
|
|
70
75
|
this.options = defaultOptions;
|
|
71
76
|
this.apiEmitter = new emitter_1.Emitter();
|
|
72
77
|
this.endpointRouter = (0, express_1.Router)();
|
|
78
|
+
this.reloadQueue = new job_queue_1.JobQueue();
|
|
73
79
|
}
|
|
74
80
|
async initialize(options = {}) {
|
|
75
81
|
this.options = {
|
|
@@ -86,27 +92,29 @@ class ExtensionManager {
|
|
|
86
92
|
}
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
reload() {
|
|
96
|
+
this.reloadQueue.enqueue(async () => {
|
|
97
|
+
if (this.isLoaded) {
|
|
98
|
+
logger_1.default.info('Reloading extensions');
|
|
99
|
+
const prevExtensions = (0, lodash_1.clone)(this.extensions);
|
|
100
|
+
await this.unload();
|
|
101
|
+
await this.load();
|
|
102
|
+
const added = this.extensions.filter((extension) => !prevExtensions.some((prevExtension) => extension.path === prevExtension.path));
|
|
103
|
+
const removed = prevExtensions.filter((prevExtension) => !this.extensions.some((extension) => prevExtension.path === extension.path));
|
|
104
|
+
this.updateWatchedExtensions(added, removed);
|
|
105
|
+
const addedExtensions = added.map((extension) => extension.name);
|
|
106
|
+
const removedExtensions = removed.map((extension) => extension.name);
|
|
107
|
+
if (addedExtensions.length > 0) {
|
|
108
|
+
logger_1.default.info(`Added extensions: ${addedExtensions.join(', ')}`);
|
|
109
|
+
}
|
|
110
|
+
if (removedExtensions.length > 0) {
|
|
111
|
+
logger_1.default.info(`Removed extensions: ${removedExtensions.join(', ')}`);
|
|
112
|
+
}
|
|
102
113
|
}
|
|
103
|
-
|
|
104
|
-
logger_1.default.
|
|
114
|
+
else {
|
|
115
|
+
logger_1.default.warn('Extensions have to be loaded before they can be reloaded');
|
|
105
116
|
}
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
logger_1.default.warn('Extensions have to be loaded before they can be reloaded');
|
|
109
|
-
}
|
|
117
|
+
});
|
|
110
118
|
}
|
|
111
119
|
getExtensionsList(type) {
|
|
112
120
|
if (type === undefined) {
|
|
@@ -255,7 +263,7 @@ class ExtensionManager {
|
|
|
255
263
|
const endpointPath = path_1.default.resolve(endpoint.path, endpoint.entrypoint);
|
|
256
264
|
const endpointInstance = require(endpointPath);
|
|
257
265
|
const config = (0, get_module_default_1.default)(endpointInstance);
|
|
258
|
-
this.registerEndpoint(config, endpointPath, this.endpointRouter);
|
|
266
|
+
this.registerEndpoint(config, endpointPath, endpoint.name, this.endpointRouter);
|
|
259
267
|
}
|
|
260
268
|
catch (error) {
|
|
261
269
|
logger_1.default.warn(`Couldn't register endpoint "${endpoint.name}"`);
|
|
@@ -350,9 +358,9 @@ class ExtensionManager {
|
|
|
350
358
|
});
|
|
351
359
|
this.apiExtensions.hooks.push(hookHandler);
|
|
352
360
|
}
|
|
353
|
-
registerEndpoint(config, path, router) {
|
|
361
|
+
registerEndpoint(config, path, name, router) {
|
|
354
362
|
const register = typeof config === 'function' ? config : config.handler;
|
|
355
|
-
const routeName = typeof config === 'function' ?
|
|
363
|
+
const routeName = typeof config === 'function' ? name : config.id;
|
|
356
364
|
const scopedRouter = express_1.default.Router();
|
|
357
365
|
router.use(`/${routeName}`, scopedRouter);
|
|
358
366
|
register(scopedRouter, {
|
package/dist/flows.d.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { OperationHandler } from '@directus/shared/types';
|
|
2
2
|
export declare function getFlowManager(): FlowManager;
|
|
3
3
|
declare class FlowManager {
|
|
4
|
+
private isLoaded;
|
|
4
5
|
private operations;
|
|
5
6
|
private triggerHandlers;
|
|
6
7
|
private operationFlowHandlers;
|
|
7
8
|
private webhookFlowHandlers;
|
|
9
|
+
private reloadQueue;
|
|
10
|
+
constructor();
|
|
8
11
|
initialize(): Promise<void>;
|
|
9
12
|
reload(): Promise<void>;
|
|
10
13
|
addOperation(id: string, operation: OperationHandler): void;
|
|
11
14
|
clearOperations(): void;
|
|
12
15
|
runOperationFlow(id: string, data: unknown, context: Record<string, unknown>): Promise<unknown>;
|
|
13
16
|
runWebhookFlow(id: string, data: unknown, context: Record<string, unknown>): Promise<unknown>;
|
|
17
|
+
private load;
|
|
18
|
+
private unload;
|
|
14
19
|
private executeFlow;
|
|
15
20
|
private executeOperation;
|
|
16
21
|
}
|
package/dist/flows.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -25,6 +29,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
29
|
exports.getFlowManager = void 0;
|
|
26
30
|
const sharedExceptions = __importStar(require("@directus/shared/exceptions"));
|
|
27
31
|
const types_1 = require("@directus/shared/types");
|
|
32
|
+
const utils_1 = require("@directus/shared/utils");
|
|
33
|
+
const fast_redact_1 = __importDefault(require("fast-redact"));
|
|
34
|
+
const lodash_1 = require("lodash");
|
|
28
35
|
const micromustache_1 = require("micromustache");
|
|
29
36
|
const node_cron_1 = require("node-cron");
|
|
30
37
|
const database_1 = __importDefault(require("./database"));
|
|
@@ -32,16 +39,14 @@ const emitter_1 = __importDefault(require("./emitter"));
|
|
|
32
39
|
const env_1 = __importDefault(require("./env"));
|
|
33
40
|
const exceptions = __importStar(require("./exceptions"));
|
|
34
41
|
const logger_1 = __importDefault(require("./logger"));
|
|
42
|
+
const messenger_1 = require("./messenger");
|
|
35
43
|
const services = __importStar(require("./services"));
|
|
36
44
|
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
45
|
const activity_1 = require("./services/activity");
|
|
40
46
|
const revisions_1 = require("./services/revisions");
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const operation_options_1 = require("./utils/operation-options");
|
|
47
|
+
const construct_flow_tree_1 = require("./utils/construct-flow-tree");
|
|
48
|
+
const get_schema_1 = require("./utils/get-schema");
|
|
49
|
+
const job_queue_1 = require("./utils/job-queue");
|
|
45
50
|
let flowManager;
|
|
46
51
|
const redactLogs = (0, fast_redact_1.default)({
|
|
47
52
|
censor: '--redacted--',
|
|
@@ -61,12 +66,59 @@ const ACCOUNTABILITY_KEY = '$accountability';
|
|
|
61
66
|
const LAST_KEY = '$last';
|
|
62
67
|
class FlowManager {
|
|
63
68
|
constructor() {
|
|
69
|
+
this.isLoaded = false;
|
|
64
70
|
this.operations = {};
|
|
65
71
|
this.triggerHandlers = [];
|
|
66
72
|
this.operationFlowHandlers = {};
|
|
67
73
|
this.webhookFlowHandlers = {};
|
|
74
|
+
this.reloadQueue = new job_queue_1.JobQueue();
|
|
75
|
+
const messenger = (0, messenger_1.getMessenger)();
|
|
76
|
+
messenger.subscribe('flows', (event) => {
|
|
77
|
+
if (event.type === 'reload') {
|
|
78
|
+
this.reloadQueue.enqueue(async () => {
|
|
79
|
+
if (this.isLoaded) {
|
|
80
|
+
await this.unload();
|
|
81
|
+
await this.load();
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
logger_1.default.warn('Flows have to be loaded before they can be reloaded');
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
});
|
|
68
89
|
}
|
|
69
90
|
async initialize() {
|
|
91
|
+
if (!this.isLoaded) {
|
|
92
|
+
await this.load();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async reload() {
|
|
96
|
+
const messenger = (0, messenger_1.getMessenger)();
|
|
97
|
+
messenger.publish('flows', { type: 'reload' });
|
|
98
|
+
}
|
|
99
|
+
addOperation(id, operation) {
|
|
100
|
+
this.operations[id] = operation;
|
|
101
|
+
}
|
|
102
|
+
clearOperations() {
|
|
103
|
+
this.operations = {};
|
|
104
|
+
}
|
|
105
|
+
async runOperationFlow(id, data, context) {
|
|
106
|
+
if (!(id in this.operationFlowHandlers)) {
|
|
107
|
+
logger_1.default.warn(`Couldn't find operation triggered flow with id "${id}"`);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const handler = this.operationFlowHandlers[id];
|
|
111
|
+
return handler(data, context);
|
|
112
|
+
}
|
|
113
|
+
async runWebhookFlow(id, data, context) {
|
|
114
|
+
if (!(id in this.webhookFlowHandlers)) {
|
|
115
|
+
logger_1.default.warn(`Couldn't find webhook or manual triggered flow with id "${id}"`);
|
|
116
|
+
throw new exceptions.ForbiddenException();
|
|
117
|
+
}
|
|
118
|
+
const handler = this.webhookFlowHandlers[id];
|
|
119
|
+
return handler(data, context);
|
|
120
|
+
}
|
|
121
|
+
async load() {
|
|
70
122
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
71
123
|
const flowsService = new services_1.FlowsService({ knex: (0, database_1.default)(), schema: await (0, get_schema_1.getSchema)() });
|
|
72
124
|
const flows = await flowsService.readByQuery({
|
|
@@ -104,7 +156,7 @@ class FlowManager {
|
|
|
104
156
|
else if (flow.options.type === 'action') {
|
|
105
157
|
const handler = (meta, context) => this.executeFlow(flow, meta, {
|
|
106
158
|
accountability: context.accountability,
|
|
107
|
-
database:
|
|
159
|
+
database: (0, database_1.default)(),
|
|
108
160
|
getSchema: context.schema ? () => context.schema : get_schema_1.getSchema,
|
|
109
161
|
});
|
|
110
162
|
events.forEach((event) => emitter_1.default.onAction(event, handler));
|
|
@@ -150,9 +202,9 @@ class FlowManager {
|
|
|
150
202
|
}
|
|
151
203
|
else if (flow.trigger === 'manual') {
|
|
152
204
|
const handler = (data, context) => {
|
|
153
|
-
var _a, _b
|
|
205
|
+
var _a, _b;
|
|
154
206
|
const enabledCollections = (_b = (_a = flow.options) === null || _a === void 0 ? void 0 : _a.collections) !== null && _b !== void 0 ? _b : [];
|
|
155
|
-
const targetCollection =
|
|
207
|
+
const targetCollection = data === null || data === void 0 ? void 0 : data.body.collection;
|
|
156
208
|
if (!targetCollection) {
|
|
157
209
|
logger_1.default.warn(`Manual trigger requires "collection" to be specified in the payload`);
|
|
158
210
|
throw new exceptions.ForbiddenException();
|
|
@@ -177,13 +229,9 @@ class FlowManager {
|
|
|
177
229
|
this.webhookFlowHandlers[`POST-${flow.id}`] = handler;
|
|
178
230
|
}
|
|
179
231
|
}
|
|
180
|
-
|
|
181
|
-
if (event.type === 'reload') {
|
|
182
|
-
this.reload();
|
|
183
|
-
}
|
|
184
|
-
});
|
|
232
|
+
this.isLoaded = true;
|
|
185
233
|
}
|
|
186
|
-
async
|
|
234
|
+
async unload() {
|
|
187
235
|
for (const trigger of this.triggerHandlers) {
|
|
188
236
|
trigger.events.forEach((event) => {
|
|
189
237
|
switch (event.type) {
|
|
@@ -202,29 +250,7 @@ class FlowManager {
|
|
|
202
250
|
this.triggerHandlers = [];
|
|
203
251
|
this.operationFlowHandlers = {};
|
|
204
252
|
this.webhookFlowHandlers = {};
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
addOperation(id, operation) {
|
|
208
|
-
this.operations[id] = operation;
|
|
209
|
-
}
|
|
210
|
-
clearOperations() {
|
|
211
|
-
this.operations = {};
|
|
212
|
-
}
|
|
213
|
-
async runOperationFlow(id, data, context) {
|
|
214
|
-
if (!(id in this.operationFlowHandlers)) {
|
|
215
|
-
logger_1.default.warn(`Couldn't find operation triggered flow with id "${id}"`);
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
const handler = this.operationFlowHandlers[id];
|
|
219
|
-
return handler(data, context);
|
|
220
|
-
}
|
|
221
|
-
async runWebhookFlow(id, data, context) {
|
|
222
|
-
if (!(id in this.webhookFlowHandlers)) {
|
|
223
|
-
logger_1.default.warn(`Couldn't find webhook or manual triggered flow with id "${id}"`);
|
|
224
|
-
throw new exceptions.ForbiddenException();
|
|
225
|
-
}
|
|
226
|
-
const handler = this.webhookFlowHandlers[id];
|
|
227
|
-
return handler(data, context);
|
|
253
|
+
this.isLoaded = false;
|
|
228
254
|
}
|
|
229
255
|
async executeFlow(flow, data = null, context = {}) {
|
|
230
256
|
var _a, _b, _c, _d, _e, _f;
|
|
@@ -288,7 +314,7 @@ class FlowManager {
|
|
|
288
314
|
return { successor: null, status: 'unknown', data: null, options: null };
|
|
289
315
|
}
|
|
290
316
|
const handler = this.operations[operation.type];
|
|
291
|
-
const options = (0,
|
|
317
|
+
const options = (0, utils_1.applyOptionsData)(operation.options, keyedData);
|
|
292
318
|
try {
|
|
293
319
|
const result = await handler(options, {
|
|
294
320
|
services,
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/logger.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/messenger.js
CHANGED
|
@@ -4,10 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getMessenger = exports.MessengerRedis = exports.MessengerMemory = void 0;
|
|
7
|
+
const utils_1 = require("@directus/shared/utils");
|
|
7
8
|
const ioredis_1 = __importDefault(require("ioredis"));
|
|
8
9
|
const env_1 = __importDefault(require("./env"));
|
|
9
10
|
const get_config_from_env_1 = require("./utils/get-config-from-env");
|
|
10
|
-
const parse_json_1 = require("./utils/parse-json");
|
|
11
11
|
class MessengerMemory {
|
|
12
12
|
constructor() {
|
|
13
13
|
this.handlers = {};
|
|
@@ -38,7 +38,7 @@ class MessengerRedis {
|
|
|
38
38
|
subscribe(channel, callback) {
|
|
39
39
|
this.sub.subscribe(`${this.namespace}:${channel}`);
|
|
40
40
|
this.sub.on('message', (messageChannel, payloadString) => {
|
|
41
|
-
const payload = (0,
|
|
41
|
+
const payload = (0, utils_1.parseJSON)(payloadString);
|
|
42
42
|
if (messageChannel === `${this.namespace}:${channel}`) {
|
|
43
43
|
callback(payload);
|
|
44
44
|
}
|
|
@@ -4,10 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.parseGraphQL = void 0;
|
|
7
|
+
const utils_1 = require("@directus/shared/utils");
|
|
7
8
|
const graphql_1 = require("graphql");
|
|
8
9
|
const exceptions_1 = require("../exceptions");
|
|
9
10
|
const async_handler_1 = __importDefault(require("../utils/async-handler"));
|
|
10
|
-
const parse_json_1 = require("../utils/parse-json");
|
|
11
11
|
exports.parseGraphQL = (0, async_handler_1.default)(async (req, res, next) => {
|
|
12
12
|
if (req.method !== 'GET' && req.method !== 'POST') {
|
|
13
13
|
throw new exceptions_1.MethodNotAllowedException('GraphQL only supports GET and POST requests.', { allow: ['GET', 'POST'] });
|
|
@@ -20,7 +20,7 @@ exports.parseGraphQL = (0, async_handler_1.default)(async (req, res, next) => {
|
|
|
20
20
|
query = req.query.query || null;
|
|
21
21
|
if (req.query.variables) {
|
|
22
22
|
try {
|
|
23
|
-
variables = (0,
|
|
23
|
+
variables = (0, utils_1.parseJSON)(req.query.variables);
|
|
24
24
|
}
|
|
25
25
|
catch {
|
|
26
26
|
throw new exceptions_1.InvalidQueryException(`Variables are invalid JSON.`);
|
|
@@ -13,14 +13,23 @@ const get_cache_headers_1 = require("../utils/get-cache-headers");
|
|
|
13
13
|
const logger_1 = __importDefault(require("../logger"));
|
|
14
14
|
const services_1 = require("../services");
|
|
15
15
|
const get_date_formatted_1 = require("../utils/get-date-formatted");
|
|
16
|
+
const get_string_byte_size_1 = require("../utils/get-string-byte-size");
|
|
17
|
+
const bytes_1 = require("bytes");
|
|
16
18
|
exports.respond = (0, async_handler_1.default)(async (req, res) => {
|
|
17
19
|
var _a, _b, _c;
|
|
18
20
|
const { cache } = (0, cache_1.getCache)();
|
|
21
|
+
let exceedsMaxSize = false;
|
|
22
|
+
if (env_1.default.CACHE_VALUE_MAX_SIZE !== false) {
|
|
23
|
+
const valueSize = res.locals.payload ? (0, get_string_byte_size_1.stringByteSize)(JSON.stringify(res.locals.payload)) : 0;
|
|
24
|
+
const maxSize = (0, bytes_1.parse)(env_1.default.CACHE_VALUE_MAX_SIZE);
|
|
25
|
+
exceedsMaxSize = valueSize > maxSize;
|
|
26
|
+
}
|
|
19
27
|
if (req.method.toLowerCase() === 'get' &&
|
|
20
28
|
env_1.default.CACHE_ENABLED === true &&
|
|
21
29
|
cache &&
|
|
22
30
|
!req.sanitizedQuery.export &&
|
|
23
|
-
res.locals.cache !== false
|
|
31
|
+
res.locals.cache !== false &&
|
|
32
|
+
exceedsMaxSize === false) {
|
|
24
33
|
const key = (0, get_cache_key_1.getCacheKey)(req);
|
|
25
34
|
try {
|
|
26
35
|
await cache.set(key, res.locals.payload, (0, ms_1.default)(env_1.default.CACHE_TTL));
|
|
@@ -27,8 +27,10 @@ const validateBatch = (scope) => (0, async_handler_1.default)(async (req, res, n
|
|
|
27
27
|
if (scope !== 'read') {
|
|
28
28
|
batchSchema = batchSchema.xor('query', 'keys');
|
|
29
29
|
}
|
|
30
|
-
// In updates, we add a required `data` that holds the update payload
|
|
30
|
+
// In updates, we add a required `data` that holds the update payload if an array isn't used
|
|
31
31
|
if (scope === 'update') {
|
|
32
|
+
if (Array.isArray(req.body))
|
|
33
|
+
return next();
|
|
32
34
|
batchSchema = batchSchema.keys({
|
|
33
35
|
data: joi_1.default.object().unknown().required(),
|
|
34
36
|
});
|