directus 9.22.4 → 9.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +5 -4
- package/dist/auth/drivers/ldap.d.ts +2 -2
- package/dist/auth/drivers/ldap.js +8 -8
- package/dist/auth/drivers/oauth2.js +2 -2
- package/dist/auth/drivers/openid.js +2 -2
- package/dist/cache.js +4 -4
- package/dist/cli/commands/schema/apply.js +19 -17
- package/dist/cli/utils/create-db-connection.d.ts +2 -1
- package/dist/cli/utils/create-env/env-stub.liquid +1 -1
- package/dist/cli/utils/drivers.d.ts +3 -9
- package/dist/constants.d.ts +2 -8
- package/dist/constants.js +3 -7
- package/dist/controllers/assets.js +5 -5
- package/dist/controllers/extensions.js +7 -7
- package/dist/controllers/files.js +1 -1
- package/dist/controllers/graphql.js +8 -0
- package/dist/controllers/schema.d.ts +2 -0
- package/dist/controllers/schema.js +98 -0
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +1 -1
- package/dist/database/helpers/schema/dialects/oracle.d.ts +4 -1
- package/dist/database/helpers/schema/dialects/oracle.js +25 -0
- package/dist/database/helpers/schema/types.d.ts +8 -6
- package/dist/database/helpers/schema/types.js +7 -1
- package/dist/database/index.d.ts +2 -1
- package/dist/database/run-ast.js +2 -2
- package/dist/env.js +9 -2
- package/dist/extensions.js +1 -1
- package/dist/flows.js +17 -8
- package/dist/middleware/cache.js +2 -2
- package/dist/middleware/respond.js +14 -9
- package/dist/operations/request/index.js +2 -1
- package/dist/operations/trigger/index.d.ts +2 -0
- package/dist/operations/trigger/index.js +26 -9
- package/dist/request/index.d.ts +5 -0
- package/dist/request/index.js +18 -0
- package/dist/request/index.test.d.ts +1 -0
- package/dist/request/request-interceptor.d.ts +2 -0
- package/dist/request/request-interceptor.js +33 -0
- package/dist/request/request-interceptor.test.d.ts +1 -0
- package/dist/request/response-interceptor.d.ts +2 -0
- package/dist/request/response-interceptor.js +9 -0
- package/dist/request/response-interceptor.test.d.ts +1 -0
- package/dist/request/validate-ip.d.ts +1 -0
- package/dist/request/validate-ip.js +27 -0
- package/dist/request/validate-ip.test.d.ts +1 -0
- package/dist/services/assets.d.ts +1 -1
- package/dist/services/assets.js +11 -2
- package/dist/services/authentication.js +5 -5
- package/dist/services/fields.js +1 -0
- package/dist/services/files.js +44 -88
- package/dist/services/graphql/index.js +14 -8
- package/dist/services/graphql/utils/process-error.js +22 -9
- package/dist/services/import-export.d.ts +4 -2
- package/dist/services/import-export.js +17 -3
- package/dist/services/import-export.test.d.ts +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/items.js +34 -15
- package/dist/services/relations.js +2 -0
- package/dist/services/roles.js +32 -11
- package/dist/services/schema.d.ts +15 -0
- package/dist/services/schema.js +58 -0
- package/dist/services/schema.test.d.ts +1 -0
- package/dist/services/shares.d.ts +2 -2
- package/dist/services/shares.js +9 -9
- package/dist/services/users.js +74 -47
- package/dist/types/assets.d.ts +1 -1
- package/dist/types/database.d.ts +3 -0
- package/dist/types/database.js +4 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/items.d.ts +5 -0
- package/dist/types/snapshot.d.ts +22 -0
- package/dist/types/snapshot.js +14 -0
- package/dist/utils/apply-diff.d.ts +9 -0
- package/dist/utils/apply-diff.js +259 -0
- package/dist/utils/apply-diff.test.d.ts +1 -0
- package/dist/utils/apply-query.js +8 -6
- package/dist/utils/apply-snapshot.d.ts +1 -3
- package/dist/utils/apply-snapshot.js +4 -234
- package/dist/utils/get-cache-headers.d.ts +3 -1
- package/dist/utils/get-cache-headers.js +20 -19
- package/dist/utils/get-cache-headers.test.d.ts +1 -0
- package/dist/utils/get-milliseconds.d.ts +4 -0
- package/dist/utils/get-milliseconds.js +15 -0
- package/dist/utils/get-milliseconds.test.d.ts +1 -0
- package/dist/utils/get-snapshot-diff.js +11 -7
- package/dist/utils/get-snapshot.js +29 -6
- package/dist/utils/get-versioned-hash.d.ts +1 -0
- package/dist/utils/get-versioned-hash.js +12 -0
- package/dist/utils/get-versioned-hash.test.d.ts +1 -0
- package/dist/utils/map-values-deep.d.ts +1 -0
- package/dist/utils/map-values-deep.js +29 -0
- package/dist/utils/map-values-deep.test.d.ts +1 -0
- package/dist/utils/sanitize-schema.d.ts +30 -0
- package/dist/utils/sanitize-schema.js +80 -0
- package/dist/utils/sanitize-schema.test.d.ts +1 -0
- package/dist/utils/track.js +3 -3
- package/dist/utils/url.js +2 -6
- package/dist/utils/url.test.d.ts +1 -0
- package/dist/utils/validate-diff.d.ts +7 -0
- package/dist/utils/validate-diff.js +114 -0
- package/dist/utils/validate-diff.test.d.ts +1 -0
- package/dist/utils/validate-query.js +1 -1
- package/dist/utils/validate-query.test.d.ts +1 -0
- package/dist/utils/validate-snapshot.d.ts +5 -0
- package/dist/utils/validate-snapshot.js +71 -0
- package/dist/utils/validate-snapshot.test.d.ts +1 -0
- package/dist/utils/with-timeout.d.ts +1 -0
- package/dist/utils/with-timeout.js +16 -0
- package/dist/webhooks.js +3 -2
- package/package.json +54 -53
|
@@ -0,0 +1,15 @@
|
|
|
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.getMilliseconds = void 0;
|
|
7
|
+
const ms_1 = __importDefault(require("ms"));
|
|
8
|
+
function getMilliseconds(value, fallback = undefined) {
|
|
9
|
+
var _a;
|
|
10
|
+
if ((typeof value !== 'string' && typeof value !== 'number') || value === '') {
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
return (_a = (0, ms_1.default)(String(value))) !== null && _a !== void 0 ? _a : fallback;
|
|
14
|
+
}
|
|
15
|
+
exports.getMilliseconds = getMilliseconds;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getSnapshotDiff = void 0;
|
|
4
4
|
const deep_diff_1 = require("deep-diff");
|
|
5
5
|
const lodash_1 = require("lodash");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
const sanitize_schema_1 = require("./sanitize-schema");
|
|
6
8
|
function getSnapshotDiff(current, after) {
|
|
7
9
|
const diffedSnapshot = {
|
|
8
10
|
collections: (0, lodash_1.orderBy)([
|
|
@@ -10,7 +12,7 @@ function getSnapshotDiff(current, after) {
|
|
|
10
12
|
const afterCollection = after.collections.find((afterCollection) => afterCollection.collection === currentCollection.collection);
|
|
11
13
|
return {
|
|
12
14
|
collection: currentCollection.collection,
|
|
13
|
-
diff: (0, deep_diff_1.diff)(currentCollection, afterCollection),
|
|
15
|
+
diff: (0, deep_diff_1.diff)((0, sanitize_schema_1.sanitizeCollection)(currentCollection), (0, sanitize_schema_1.sanitizeCollection)(afterCollection)),
|
|
14
16
|
};
|
|
15
17
|
}),
|
|
16
18
|
...after.collections
|
|
@@ -20,16 +22,18 @@ function getSnapshotDiff(current, after) {
|
|
|
20
22
|
})
|
|
21
23
|
.map((afterCollection) => ({
|
|
22
24
|
collection: afterCollection.collection,
|
|
23
|
-
diff: (0, deep_diff_1.diff)(undefined, afterCollection),
|
|
25
|
+
diff: (0, deep_diff_1.diff)(undefined, (0, sanitize_schema_1.sanitizeCollection)(afterCollection)),
|
|
24
26
|
})),
|
|
25
27
|
].filter((obj) => Array.isArray(obj.diff)), 'collection'),
|
|
26
28
|
fields: (0, lodash_1.orderBy)([
|
|
27
29
|
...current.fields.map((currentField) => {
|
|
30
|
+
var _a, _b;
|
|
28
31
|
const afterField = after.fields.find((afterField) => afterField.collection === currentField.collection && afterField.field === currentField.field);
|
|
32
|
+
const isAutoIncrementPrimaryKey = !!((_a = currentField.schema) === null || _a === void 0 ? void 0 : _a.is_primary_key) && !!((_b = currentField.schema) === null || _b === void 0 ? void 0 : _b.has_auto_increment);
|
|
29
33
|
return {
|
|
30
34
|
collection: currentField.collection,
|
|
31
35
|
field: currentField.field,
|
|
32
|
-
diff: (0, deep_diff_1.diff)(currentField, afterField),
|
|
36
|
+
diff: (0, deep_diff_1.diff)((0, sanitize_schema_1.sanitizeField)(currentField, isAutoIncrementPrimaryKey), (0, sanitize_schema_1.sanitizeField)(afterField, isAutoIncrementPrimaryKey)),
|
|
33
37
|
};
|
|
34
38
|
}),
|
|
35
39
|
...after.fields
|
|
@@ -40,7 +44,7 @@ function getSnapshotDiff(current, after) {
|
|
|
40
44
|
.map((afterField) => ({
|
|
41
45
|
collection: afterField.collection,
|
|
42
46
|
field: afterField.field,
|
|
43
|
-
diff: (0, deep_diff_1.diff)(undefined, afterField),
|
|
47
|
+
diff: (0, deep_diff_1.diff)(undefined, (0, sanitize_schema_1.sanitizeField)(afterField)),
|
|
44
48
|
})),
|
|
45
49
|
].filter((obj) => Array.isArray(obj.diff)), ['collection']),
|
|
46
50
|
relations: (0, lodash_1.orderBy)([
|
|
@@ -50,7 +54,7 @@ function getSnapshotDiff(current, after) {
|
|
|
50
54
|
collection: currentRelation.collection,
|
|
51
55
|
field: currentRelation.field,
|
|
52
56
|
related_collection: currentRelation.related_collection,
|
|
53
|
-
diff: (0, deep_diff_1.diff)(currentRelation, afterRelation),
|
|
57
|
+
diff: (0, deep_diff_1.diff)((0, sanitize_schema_1.sanitizeRelation)(currentRelation), (0, sanitize_schema_1.sanitizeRelation)(afterRelation)),
|
|
54
58
|
};
|
|
55
59
|
}),
|
|
56
60
|
...after.relations
|
|
@@ -62,7 +66,7 @@ function getSnapshotDiff(current, after) {
|
|
|
62
66
|
collection: afterRelation.collection,
|
|
63
67
|
field: afterRelation.field,
|
|
64
68
|
related_collection: afterRelation.related_collection,
|
|
65
|
-
diff: (0, deep_diff_1.diff)(undefined, afterRelation),
|
|
69
|
+
diff: (0, deep_diff_1.diff)(undefined, (0, sanitize_schema_1.sanitizeRelation)(afterRelation)),
|
|
66
70
|
})),
|
|
67
71
|
].filter((obj) => Array.isArray(obj.diff)), ['collection']),
|
|
68
72
|
};
|
|
@@ -70,7 +74,7 @@ function getSnapshotDiff(current, after) {
|
|
|
70
74
|
* When you delete a collection, we don't have to individually drop all the fields/relations as well
|
|
71
75
|
*/
|
|
72
76
|
const deletedCollections = diffedSnapshot.collections
|
|
73
|
-
.filter((collection) => { var _a; return ((_a = collection.diff) === null || _a === void 0 ? void 0 : _a[0].kind) ===
|
|
77
|
+
.filter((collection) => { var _a; return ((_a = collection.diff) === null || _a === void 0 ? void 0 : _a[0].kind) === types_1.DiffKind.DELETE; })
|
|
74
78
|
.map(({ collection }) => collection);
|
|
75
79
|
diffedSnapshot.fields = diffedSnapshot.fields.filter((field) => deletedCollections.includes(field.collection) === false);
|
|
76
80
|
diffedSnapshot.relations = diffedSnapshot.relations.filter((relation) => deletedCollections.includes(relation.collection) === false);
|
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
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);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
4
24
|
};
|
|
5
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
26
|
exports.getSnapshot = void 0;
|
|
7
|
-
const database_1 =
|
|
27
|
+
const database_1 = __importStar(require("../database"));
|
|
8
28
|
const get_schema_1 = require("./get-schema");
|
|
9
29
|
const services_1 = require("../services");
|
|
10
30
|
const package_json_1 = require("../../package.json");
|
|
11
31
|
const lodash_1 = require("lodash");
|
|
32
|
+
const sanitize_schema_1 = require("./sanitize-schema");
|
|
12
33
|
async function getSnapshot(options) {
|
|
13
34
|
var _a, _b;
|
|
14
35
|
const database = (_a = options === null || options === void 0 ? void 0 : options.database) !== null && _a !== void 0 ? _a : (0, database_1.default)();
|
|
36
|
+
const vendor = (0, database_1.getDatabaseClient)(database);
|
|
15
37
|
const schema = (_b = options === null || options === void 0 ? void 0 : options.schema) !== null && _b !== void 0 ? _b : (await (0, get_schema_1.getSchema)({ database, bypassCache: true }));
|
|
16
38
|
const collectionsService = new services_1.CollectionsService({ knex: database, schema });
|
|
17
39
|
const fieldsService = new services_1.FieldsService({ knex: database, schema });
|
|
@@ -30,9 +52,10 @@ async function getSnapshot(options) {
|
|
|
30
52
|
return {
|
|
31
53
|
version: 1,
|
|
32
54
|
directus: package_json_1.version,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
55
|
+
vendor,
|
|
56
|
+
collections: collectionsSorted.map((collection) => (0, sanitize_schema_1.sanitizeCollection)(collection)),
|
|
57
|
+
fields: fieldsSorted.map((field) => (0, sanitize_schema_1.sanitizeField)(field)),
|
|
58
|
+
relations: relationsSorted.map((relation) => (0, sanitize_schema_1.sanitizeRelation)(relation)),
|
|
36
59
|
};
|
|
37
60
|
}
|
|
38
61
|
exports.getSnapshot = getSnapshot;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getVersionedHash(item: Record<string, any>): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
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.getVersionedHash = void 0;
|
|
7
|
+
const object_hash_1 = __importDefault(require("object-hash"));
|
|
8
|
+
const package_json_1 = require("../../package.json");
|
|
9
|
+
function getVersionedHash(item) {
|
|
10
|
+
return (0, object_hash_1.default)({ item, version: package_json_1.version });
|
|
11
|
+
}
|
|
12
|
+
exports.getVersionedHash = getVersionedHash;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function mapValuesDeep(obj: Record<string, any>, fn: (key: string, value: any) => any): Record<string, any>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapValuesDeep = void 0;
|
|
4
|
+
function mapValuesDeep(obj, fn) {
|
|
5
|
+
return recurse(obj);
|
|
6
|
+
function recurse(obj, prefix = '') {
|
|
7
|
+
if (Array.isArray(obj)) {
|
|
8
|
+
return obj.map((value, index) => {
|
|
9
|
+
if (typeof value === 'object' && value !== null) {
|
|
10
|
+
return recurse(value, prefix + `[${index}]`);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
return fn(prefix + `[${index}]`, value);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => {
|
|
19
|
+
if (typeof value === 'object' && value !== null) {
|
|
20
|
+
return [key, recurse(value, prefix + (prefix ? '.' : '') + key)];
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return [key, fn(prefix + (prefix ? '.' : '') + key, value)];
|
|
24
|
+
}
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.mapValuesDeep = mapValuesDeep;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Field, Relation } from '@directus/shared/types';
|
|
2
|
+
import { Collection } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Pick certain database vendor specific collection properties that should be compared when performing diff
|
|
5
|
+
*
|
|
6
|
+
* @param collection collection to sanitize
|
|
7
|
+
* @returns sanitized collection
|
|
8
|
+
*
|
|
9
|
+
* @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/table.ts}
|
|
10
|
+
*/
|
|
11
|
+
export declare function sanitizeCollection(collection: Collection | undefined): Partial<Collection> | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Pick certain database vendor specific field properties that should be compared when performing diff
|
|
14
|
+
*
|
|
15
|
+
* @param field field to sanitize
|
|
16
|
+
* @param sanitizeAllSchema Whether or not the whole field schema should be sanitized. Mainly used to prevent modifying autoincrement fields
|
|
17
|
+
* @returns sanitized field
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/column.ts}
|
|
20
|
+
*/
|
|
21
|
+
export declare function sanitizeField(field: Field | undefined, sanitizeAllSchema?: boolean): Partial<Field> | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Pick certain database vendor specific relation properties that should be compared when performing diff
|
|
24
|
+
*
|
|
25
|
+
* @param relation relation to sanitize
|
|
26
|
+
* @returns sanitized relation
|
|
27
|
+
*
|
|
28
|
+
* @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/foreign-key.ts}
|
|
29
|
+
*/
|
|
30
|
+
export declare function sanitizeRelation(relation: Relation | undefined): Partial<Relation> | undefined;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeRelation = exports.sanitizeField = exports.sanitizeCollection = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
/**
|
|
6
|
+
* Pick certain database vendor specific collection properties that should be compared when performing diff
|
|
7
|
+
*
|
|
8
|
+
* @param collection collection to sanitize
|
|
9
|
+
* @returns sanitized collection
|
|
10
|
+
*
|
|
11
|
+
* @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/table.ts}
|
|
12
|
+
*/
|
|
13
|
+
function sanitizeCollection(collection) {
|
|
14
|
+
if (!collection)
|
|
15
|
+
return collection;
|
|
16
|
+
return (0, lodash_1.pick)(collection, ['collection', 'fields', 'meta', 'schema.name']);
|
|
17
|
+
}
|
|
18
|
+
exports.sanitizeCollection = sanitizeCollection;
|
|
19
|
+
/**
|
|
20
|
+
* Pick certain database vendor specific field properties that should be compared when performing diff
|
|
21
|
+
*
|
|
22
|
+
* @param field field to sanitize
|
|
23
|
+
* @param sanitizeAllSchema Whether or not the whole field schema should be sanitized. Mainly used to prevent modifying autoincrement fields
|
|
24
|
+
* @returns sanitized field
|
|
25
|
+
*
|
|
26
|
+
* @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/column.ts}
|
|
27
|
+
*/
|
|
28
|
+
function sanitizeField(field, sanitizeAllSchema = false) {
|
|
29
|
+
if (!field)
|
|
30
|
+
return field;
|
|
31
|
+
const defaultPaths = ['collection', 'field', 'type', 'meta', 'name', 'children'];
|
|
32
|
+
const pickedPaths = sanitizeAllSchema
|
|
33
|
+
? defaultPaths
|
|
34
|
+
: [
|
|
35
|
+
...defaultPaths,
|
|
36
|
+
'schema.name',
|
|
37
|
+
'schema.table',
|
|
38
|
+
'schema.data_type',
|
|
39
|
+
'schema.default_value',
|
|
40
|
+
'schema.max_length',
|
|
41
|
+
'schema.numeric_precision',
|
|
42
|
+
'schema.numeric_scale',
|
|
43
|
+
'schema.is_nullable',
|
|
44
|
+
'schema.is_unique',
|
|
45
|
+
'schema.is_primary_key',
|
|
46
|
+
'schema.is_generated',
|
|
47
|
+
'schema.generation_expression',
|
|
48
|
+
'schema.has_auto_increment',
|
|
49
|
+
'schema.foreign_key_table',
|
|
50
|
+
'schema.foreign_key_column',
|
|
51
|
+
];
|
|
52
|
+
return (0, lodash_1.pick)(field, pickedPaths);
|
|
53
|
+
}
|
|
54
|
+
exports.sanitizeField = sanitizeField;
|
|
55
|
+
/**
|
|
56
|
+
* Pick certain database vendor specific relation properties that should be compared when performing diff
|
|
57
|
+
*
|
|
58
|
+
* @param relation relation to sanitize
|
|
59
|
+
* @returns sanitized relation
|
|
60
|
+
*
|
|
61
|
+
* @see {@link https://github.com/knex/knex-schema-inspector/blob/master/lib/types/foreign-key.ts}
|
|
62
|
+
*/
|
|
63
|
+
function sanitizeRelation(relation) {
|
|
64
|
+
if (!relation)
|
|
65
|
+
return relation;
|
|
66
|
+
return (0, lodash_1.pick)(relation, [
|
|
67
|
+
'collection',
|
|
68
|
+
'field',
|
|
69
|
+
'related_collection',
|
|
70
|
+
'meta',
|
|
71
|
+
'schema.table',
|
|
72
|
+
'schema.column',
|
|
73
|
+
'schema.foreign_key_table',
|
|
74
|
+
'schema.foreign_key_column',
|
|
75
|
+
'schema.constraint_name',
|
|
76
|
+
'schema.on_update',
|
|
77
|
+
'schema.on_delete',
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
exports.sanitizeRelation = sanitizeRelation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils/track.js
CHANGED
|
@@ -4,14 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.track = void 0;
|
|
7
|
-
const ms_1 = __importDefault(require("ms"));
|
|
8
7
|
const node_machine_id_1 = require("node-machine-id");
|
|
9
8
|
const os_1 = __importDefault(require("os"));
|
|
10
9
|
// @ts-ignore
|
|
10
|
+
const utils_1 = require("@directus/shared/utils");
|
|
11
11
|
const package_json_1 = require("../../package.json");
|
|
12
12
|
const env_1 = __importDefault(require("../env"));
|
|
13
13
|
const logger_1 = __importDefault(require("../logger"));
|
|
14
|
-
const
|
|
14
|
+
const get_milliseconds_1 = require("./get-milliseconds");
|
|
15
15
|
async function track(event) {
|
|
16
16
|
const axios = (await import('axios')).default;
|
|
17
17
|
if (env_1.default.TELEMETRY !== false) {
|
|
@@ -48,7 +48,7 @@ async function getEnvInfo(event) {
|
|
|
48
48
|
},
|
|
49
49
|
cache: {
|
|
50
50
|
enabled: env_1.default.CACHE_ENABLED,
|
|
51
|
-
ttl: (0,
|
|
51
|
+
ttl: (0, get_milliseconds_1.getMilliseconds)(env_1.default.CACHE_TTL),
|
|
52
52
|
store: env_1.default.CACHE_STORE,
|
|
53
53
|
},
|
|
54
54
|
storage: {
|
package/dist/utils/url.js
CHANGED
|
@@ -49,12 +49,8 @@ class Url {
|
|
|
49
49
|
const host = (_a = this.host) !== null && _a !== void 0 ? _a : '';
|
|
50
50
|
const port = this.port !== null ? `:${this.port}` : '';
|
|
51
51
|
const origin = `${this.host !== null ? `${protocol}//` : ''}${host}${port}`;
|
|
52
|
-
const path = `/${this.path.join('/')}
|
|
53
|
-
const query = Object.keys(this.query).length !== 0
|
|
54
|
-
? `?${Object.entries(this.query)
|
|
55
|
-
.map(([k, v]) => `${k}=${v}`)
|
|
56
|
-
.join('&')}`
|
|
57
|
-
: '';
|
|
52
|
+
const path = this.path.length ? `/${this.path.join('/')}` : '';
|
|
53
|
+
const query = Object.keys(this.query).length !== 0 ? `?${new URLSearchParams(this.query).toString()}` : '';
|
|
58
54
|
const hash = this.hash !== null ? `#${this.hash}` : '';
|
|
59
55
|
return `${!rootRelative ? origin : ''}${path}${query}${hash}`;
|
|
60
56
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SnapshotDiffWithHash, SnapshotWithHash } from '../types/snapshot';
|
|
2
|
+
/**
|
|
3
|
+
* Validates the diff against the current schema snapshot.
|
|
4
|
+
*
|
|
5
|
+
* @returns True if the diff can be applied (valid & not empty).
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateApplyDiff(applyDiff: SnapshotDiffWithHash, currentSnapshotWithHash: SnapshotWithHash): boolean;
|
|
@@ -0,0 +1,114 @@
|
|
|
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.validateApplyDiff = void 0;
|
|
7
|
+
const joi_1 = __importDefault(require("joi"));
|
|
8
|
+
const index_1 = require("../index");
|
|
9
|
+
const snapshot_1 = require("../types/snapshot");
|
|
10
|
+
const deepDiffSchema = joi_1.default.object({
|
|
11
|
+
kind: joi_1.default.string()
|
|
12
|
+
.valid(...Object.values(snapshot_1.DiffKind))
|
|
13
|
+
.required(),
|
|
14
|
+
path: joi_1.default.array().items(joi_1.default.string()),
|
|
15
|
+
lhs: joi_1.default.object().when('kind', { is: [snapshot_1.DiffKind.DELETE, snapshot_1.DiffKind.EDIT], then: joi_1.default.required() }),
|
|
16
|
+
rhs: joi_1.default.object().when('kind', { is: [snapshot_1.DiffKind.NEW, snapshot_1.DiffKind.EDIT], then: joi_1.default.required() }),
|
|
17
|
+
index: joi_1.default.number().when('kind', { is: snapshot_1.DiffKind.ARRAY, then: joi_1.default.required() }),
|
|
18
|
+
item: joi_1.default.link('/').when('kind', { is: snapshot_1.DiffKind.ARRAY, then: joi_1.default.required() }),
|
|
19
|
+
});
|
|
20
|
+
const applyJoiSchema = joi_1.default.object({
|
|
21
|
+
hash: joi_1.default.string().required(),
|
|
22
|
+
diff: joi_1.default.object({
|
|
23
|
+
collections: joi_1.default.array()
|
|
24
|
+
.items(joi_1.default.object({
|
|
25
|
+
collection: joi_1.default.string().required(),
|
|
26
|
+
diff: joi_1.default.array().items(deepDiffSchema).required(),
|
|
27
|
+
}))
|
|
28
|
+
.required(),
|
|
29
|
+
fields: joi_1.default.array()
|
|
30
|
+
.items(joi_1.default.object({
|
|
31
|
+
collection: joi_1.default.string().required(),
|
|
32
|
+
field: joi_1.default.string().required(),
|
|
33
|
+
diff: joi_1.default.array().items(deepDiffSchema).required(),
|
|
34
|
+
}))
|
|
35
|
+
.required(),
|
|
36
|
+
relations: joi_1.default.array()
|
|
37
|
+
.items(joi_1.default.object({
|
|
38
|
+
collection: joi_1.default.string().required(),
|
|
39
|
+
field: joi_1.default.string().required(),
|
|
40
|
+
related_collection: joi_1.default.string(),
|
|
41
|
+
diff: joi_1.default.array().items(deepDiffSchema).required(),
|
|
42
|
+
}))
|
|
43
|
+
.required(),
|
|
44
|
+
}).required(),
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Validates the diff against the current schema snapshot.
|
|
48
|
+
*
|
|
49
|
+
* @returns True if the diff can be applied (valid & not empty).
|
|
50
|
+
*/
|
|
51
|
+
function validateApplyDiff(applyDiff, currentSnapshotWithHash) {
|
|
52
|
+
var _a, _b, _c, _d, _e, _f;
|
|
53
|
+
const { error } = applyJoiSchema.validate(applyDiff);
|
|
54
|
+
if (error)
|
|
55
|
+
throw new index_1.InvalidPayloadException(error.message);
|
|
56
|
+
// No changes to apply
|
|
57
|
+
if (applyDiff.diff.collections.length === 0 &&
|
|
58
|
+
applyDiff.diff.fields.length === 0 &&
|
|
59
|
+
applyDiff.diff.relations.length === 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
// Diff can be applied due to matching hash
|
|
63
|
+
if (applyDiff.hash === currentSnapshotWithHash.hash)
|
|
64
|
+
return true;
|
|
65
|
+
for (const diffCollection of applyDiff.diff.collections) {
|
|
66
|
+
const collection = diffCollection.collection;
|
|
67
|
+
if (((_a = diffCollection.diff[0]) === null || _a === void 0 ? void 0 : _a.kind) === snapshot_1.DiffKind.NEW) {
|
|
68
|
+
const existingCollection = currentSnapshotWithHash.collections.find((c) => c.collection === diffCollection.collection);
|
|
69
|
+
if (existingCollection) {
|
|
70
|
+
throw new index_1.InvalidPayloadException(`Provided diff is trying to create collection "${collection}" but it already exists. Please generate a new diff and try again.`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (((_b = diffCollection.diff[0]) === null || _b === void 0 ? void 0 : _b.kind) === snapshot_1.DiffKind.DELETE) {
|
|
74
|
+
const existingCollection = currentSnapshotWithHash.collections.find((c) => c.collection === diffCollection.collection);
|
|
75
|
+
if (!existingCollection) {
|
|
76
|
+
throw new index_1.InvalidPayloadException(`Provided diff is trying to delete collection "${collection}" but it does not exist. Please generate a new diff and try again.`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const diffField of applyDiff.diff.fields) {
|
|
81
|
+
const field = `${diffField.collection}.${diffField.field}`;
|
|
82
|
+
if (((_c = diffField.diff[0]) === null || _c === void 0 ? void 0 : _c.kind) === snapshot_1.DiffKind.NEW) {
|
|
83
|
+
const existingField = currentSnapshotWithHash.fields.find((f) => f.collection === diffField.collection && f.field === diffField.field);
|
|
84
|
+
if (existingField) {
|
|
85
|
+
throw new index_1.InvalidPayloadException(`Provided diff is trying to create field "${field}" but it already exists. Please generate a new diff and try again.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (((_d = diffField.diff[0]) === null || _d === void 0 ? void 0 : _d.kind) === snapshot_1.DiffKind.DELETE) {
|
|
89
|
+
const existingField = currentSnapshotWithHash.fields.find((f) => f.collection === diffField.collection && f.field === diffField.field);
|
|
90
|
+
if (!existingField) {
|
|
91
|
+
throw new index_1.InvalidPayloadException(`Provided diff is trying to delete field "${field}" but it does not exist. Please generate a new diff and try again.`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const diffRelation of applyDiff.diff.relations) {
|
|
96
|
+
let relation = `${diffRelation.collection}.${diffRelation.field}`;
|
|
97
|
+
if (diffRelation.related_collection)
|
|
98
|
+
relation += `-> ${diffRelation.related_collection}`;
|
|
99
|
+
if (((_e = diffRelation.diff[0]) === null || _e === void 0 ? void 0 : _e.kind) === snapshot_1.DiffKind.NEW) {
|
|
100
|
+
const existingRelation = currentSnapshotWithHash.relations.find((r) => r.collection === diffRelation.collection && r.field === diffRelation.field);
|
|
101
|
+
if (existingRelation) {
|
|
102
|
+
throw new index_1.InvalidPayloadException(`Provided diff is trying to create relation "${relation}" but it already exists. Please generate a new diff and try again.`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (((_f = diffRelation.diff[0]) === null || _f === void 0 ? void 0 : _f.kind) === snapshot_1.DiffKind.DELETE) {
|
|
106
|
+
const existingRelation = currentSnapshotWithHash.relations.find((r) => r.collection === diffRelation.collection && r.field === diffRelation.field);
|
|
107
|
+
if (!existingRelation) {
|
|
108
|
+
throw new index_1.InvalidPayloadException(`Provided diff is trying to delete relation "${relation}" but it does not exist. Please generate a new diff and try again.`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
throw new index_1.InvalidPayloadException(`Provided hash does not match the current instance's schema hash, indicating the schema has changed after this diff was generated. Please generate a new diff and try again.`);
|
|
113
|
+
}
|
|
114
|
+
exports.validateApplyDiff = validateApplyDiff;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -20,7 +20,7 @@ const querySchema = joi_1.default.object({
|
|
|
20
20
|
page: joi_1.default.number().integer().min(0),
|
|
21
21
|
meta: joi_1.default.array().items(joi_1.default.string().valid('total_count', 'filter_count')),
|
|
22
22
|
search: joi_1.default.string(),
|
|
23
|
-
export: joi_1.default.string().valid('
|
|
23
|
+
export: joi_1.default.string().valid('csv', 'json', 'xml', 'yaml'),
|
|
24
24
|
aggregate: joi_1.default.object(),
|
|
25
25
|
deep: joi_1.default.object(),
|
|
26
26
|
alias: joi_1.default.object(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
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.validateSnapshot = void 0;
|
|
7
|
+
const package_json_1 = require("../../package.json");
|
|
8
|
+
const exceptions_1 = require("../exceptions");
|
|
9
|
+
const database_1 = require("../database");
|
|
10
|
+
const joi_1 = __importDefault(require("joi"));
|
|
11
|
+
const constants_1 = require("@directus/shared/constants");
|
|
12
|
+
const constants_2 = require("../constants");
|
|
13
|
+
const types_1 = require("../types");
|
|
14
|
+
const snapshotJoiSchema = joi_1.default.object({
|
|
15
|
+
version: joi_1.default.number().valid(1).required(),
|
|
16
|
+
directus: joi_1.default.string().required(),
|
|
17
|
+
vendor: joi_1.default.string()
|
|
18
|
+
.valid(...types_1.DatabaseClients)
|
|
19
|
+
.optional(),
|
|
20
|
+
collections: joi_1.default.array().items(joi_1.default.object({
|
|
21
|
+
collection: joi_1.default.string(),
|
|
22
|
+
meta: joi_1.default.any(),
|
|
23
|
+
schema: joi_1.default.object({
|
|
24
|
+
name: joi_1.default.string(),
|
|
25
|
+
}),
|
|
26
|
+
})),
|
|
27
|
+
fields: joi_1.default.array().items(joi_1.default.object({
|
|
28
|
+
collection: joi_1.default.string(),
|
|
29
|
+
field: joi_1.default.string(),
|
|
30
|
+
meta: joi_1.default.any(),
|
|
31
|
+
schema: joi_1.default.object({
|
|
32
|
+
default_value: joi_1.default.any(),
|
|
33
|
+
max_length: [joi_1.default.number(), joi_1.default.string(), joi_1.default.valid(null)],
|
|
34
|
+
is_nullable: joi_1.default.bool(),
|
|
35
|
+
})
|
|
36
|
+
.unknown()
|
|
37
|
+
.allow(null),
|
|
38
|
+
type: joi_1.default.string()
|
|
39
|
+
.valid(...constants_1.TYPES, ...constants_2.ALIAS_TYPES)
|
|
40
|
+
.allow(null),
|
|
41
|
+
})),
|
|
42
|
+
relations: joi_1.default.array().items(joi_1.default.object({
|
|
43
|
+
collection: joi_1.default.string(),
|
|
44
|
+
field: joi_1.default.string(),
|
|
45
|
+
meta: joi_1.default.any(),
|
|
46
|
+
related_collection: joi_1.default.any(),
|
|
47
|
+
schema: joi_1.default.any(),
|
|
48
|
+
})),
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Validates the snapshot against the current instance.
|
|
52
|
+
**/
|
|
53
|
+
function validateSnapshot(snapshot, force = false) {
|
|
54
|
+
const { error } = snapshotJoiSchema.validate(snapshot);
|
|
55
|
+
if (error)
|
|
56
|
+
throw new exceptions_1.InvalidPayloadException(error.message);
|
|
57
|
+
// Bypass checks when "force" option is enabled
|
|
58
|
+
if (force)
|
|
59
|
+
return;
|
|
60
|
+
if (snapshot.directus !== package_json_1.version) {
|
|
61
|
+
throw new exceptions_1.InvalidPayloadException(`Provided snapshot's directus version ${snapshot.directus} does not match the current instance's version ${package_json_1.version}. You can bypass this check by passing the "force" query parameter.`);
|
|
62
|
+
}
|
|
63
|
+
if (!snapshot.vendor) {
|
|
64
|
+
throw new exceptions_1.InvalidPayloadException('Provided snapshot does not contain the "vendor" property. You can bypass this check by passing the "force" query parameter.');
|
|
65
|
+
}
|
|
66
|
+
const currentVendor = (0, database_1.getDatabaseClient)();
|
|
67
|
+
if (snapshot.vendor !== currentVendor) {
|
|
68
|
+
throw new exceptions_1.InvalidPayloadException(`Provided snapshot's vendor ${snapshot.vendor} does not match the current instance's vendor ${currentVendor}. You can bypass this check by passing the "force" query parameter.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.validateSnapshot = validateSnapshot;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const withTimeout: <T extends (...args: any[]) => Promise<unknown>>(prom: T, ms: number, err?: Error) => T;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withTimeout = void 0;
|
|
4
|
+
const withTimeout = (prom, ms, err = new Error('Promise execution timed out')) => {
|
|
5
|
+
return ((...args) => {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
setTimeout(() => {
|
|
8
|
+
reject(err);
|
|
9
|
+
}, ms);
|
|
10
|
+
prom(...args)
|
|
11
|
+
.then(resolve)
|
|
12
|
+
.catch(reject);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
exports.withTimeout = withTimeout;
|
package/dist/webhooks.js
CHANGED
|
@@ -7,9 +7,10 @@ exports.unregister = exports.register = exports.reload = exports.init = void 0;
|
|
|
7
7
|
const database_1 = __importDefault(require("./database"));
|
|
8
8
|
const emitter_1 = __importDefault(require("./emitter"));
|
|
9
9
|
const logger_1 = __importDefault(require("./logger"));
|
|
10
|
+
const messenger_1 = require("./messenger");
|
|
11
|
+
const index_1 = require("./request/index");
|
|
10
12
|
const services_1 = require("./services");
|
|
11
13
|
const get_schema_1 = require("./utils/get-schema");
|
|
12
|
-
const messenger_1 = require("./messenger");
|
|
13
14
|
const job_queue_1 = require("./utils/job-queue");
|
|
14
15
|
let registered = [];
|
|
15
16
|
const reloadQueue = new job_queue_1.JobQueue();
|
|
@@ -52,9 +53,9 @@ function unregister() {
|
|
|
52
53
|
exports.unregister = unregister;
|
|
53
54
|
function createHandler(webhook, event) {
|
|
54
55
|
return async (meta, context) => {
|
|
55
|
-
const axios = (await import('axios')).default;
|
|
56
56
|
if (webhook.collections.includes(meta.collection) === false)
|
|
57
57
|
return;
|
|
58
|
+
const axios = await (0, index_1.getAxios)();
|
|
58
59
|
const webhookPayload = {
|
|
59
60
|
event,
|
|
60
61
|
accountability: context.accountability
|