@directus/api 35.1.0 → 36.0.0-rc.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/ai/chat/models/chat-request.js +48 -48
- package/dist/ai/chat/models/object-request.js +6 -6
- package/dist/ai/chat/models/providers.js +14 -14
- package/dist/ai/chat/utils/parse-json-schema-7.js +22 -22
- package/dist/ai/mcp/server.js +44 -6
- package/dist/ai/mcp/utils.js +31 -0
- package/dist/ai/tools/assets/index.js +3 -3
- package/dist/ai/tools/collections/index.js +18 -18
- package/dist/ai/tools/fields/index.js +18 -18
- package/dist/ai/tools/files/index.js +18 -18
- package/dist/ai/tools/flows/index.js +16 -16
- package/dist/ai/tools/folders/index.js +18 -18
- package/dist/ai/tools/items/index.js +17 -17
- package/dist/ai/tools/operations/index.js +16 -16
- package/dist/ai/tools/relations/index.js +22 -22
- package/dist/ai/tools/schema/index.js +3 -3
- package/dist/ai/tools/schema.js +159 -159
- package/dist/ai/tools/system/index.js +3 -3
- package/dist/ai/tools/trigger-flow/index.js +3 -3
- package/dist/app.js +33 -9
- package/dist/auth/drivers/ldap.js +3 -1
- package/dist/auth/drivers/local.js +2 -0
- package/dist/auth/drivers/oauth2.js +3 -1
- package/dist/auth/drivers/openid.js +3 -1
- package/dist/auth/drivers/saml.js +2 -0
- package/dist/auth/utils/check-local-disabled.js +16 -0
- package/dist/auth/utils/check-sso-enabled.js +14 -0
- package/dist/auth.js +8 -5
- package/dist/cli/commands/bootstrap/index.js +3 -0
- package/dist/cli/commands/cache/clear.js +6 -1
- package/dist/cli/commands/roles/create.js +4 -1
- package/dist/cli/commands/users/create.js +3 -0
- package/dist/constants.js +8 -1
- package/dist/controllers/access.js +1 -1
- package/dist/controllers/activity.js +2 -1
- package/dist/controllers/assets.js +45 -1
- package/dist/controllers/auth.js +13 -5
- package/dist/controllers/collections.js +1 -1
- package/dist/controllers/comments.js +1 -1
- package/dist/controllers/dashboards.js +1 -1
- package/dist/controllers/fields.js +1 -1
- package/dist/controllers/files.js +3 -1
- package/dist/controllers/flows.js +6 -5
- package/dist/controllers/folders.js +1 -1
- package/dist/controllers/graphql.js +2 -0
- package/dist/controllers/items.js +3 -1
- package/dist/controllers/license.js +119 -0
- package/dist/controllers/mcp/index.js +38 -0
- package/dist/controllers/mcp/oauth-clients.js +68 -0
- package/dist/controllers/mcp/oauth-consent-page.js +316 -0
- package/dist/controllers/mcp/oauth.js +381 -0
- package/dist/controllers/mcp/templates/oauth-consent.liquid +62 -0
- package/dist/controllers/mcp/templates/oauth-error.liquid +28 -0
- package/dist/controllers/notifications.js +1 -1
- package/dist/controllers/operations.js +1 -1
- package/dist/controllers/panels.js +1 -1
- package/dist/controllers/permissions.js +1 -1
- package/dist/controllers/policies.js +1 -1
- package/dist/controllers/presets.js +1 -1
- package/dist/controllers/revisions.js +3 -2
- package/dist/controllers/roles.js +1 -1
- package/dist/controllers/schema.js +2 -2
- package/dist/controllers/server.js +38 -9
- package/dist/controllers/shares.js +1 -1
- package/dist/controllers/translations.js +1 -1
- package/dist/controllers/users.js +1 -1
- package/dist/controllers/utils.js +2 -2
- package/dist/controllers/versions.js +12 -5
- package/dist/database/get-ast-from-query/lib/convert-wildcards.js +10 -1
- package/dist/database/get-ast-from-query/lib/parse-fields.js +2 -1
- package/dist/database/helpers/fn/dialects/mysql.js +7 -12
- package/dist/database/helpers/fn/dialects/oracle.js +3 -4
- package/dist/database/helpers/fn/dialects/postgres.js +4 -26
- package/dist/database/helpers/fn/json/mysql-json-path.js +22 -0
- package/dist/database/helpers/fn/json/parse-function.js +14 -6
- package/dist/database/helpers/fn/json/postgres-json-path.js +54 -0
- package/dist/database/migrations/20260110A-add-ai-provider-settings.js +4 -4
- package/dist/database/migrations/20260217A-null-item-versions.js +14 -0
- package/dist/database/migrations/20260312A-add-ai-translation-settings.js +18 -0
- package/dist/database/migrations/20260507A-add-licensing.js +22 -0
- package/dist/database/migrations/20260512A-add-autosave-revision-interval.js +14 -0
- package/dist/database/migrations/20260512B-add-mcp-oauth.js +87 -0
- package/dist/database/run-ast/lib/apply-query/filter/operator.js +116 -33
- package/dist/database/run-ast/lib/apply-query/index.js +4 -1
- package/dist/database/run-ast/lib/apply-query/sort.js +17 -7
- package/dist/database/run-ast/lib/get-db-query.js +21 -9
- package/dist/database/run-ast/lib/parse-current-level.js +2 -1
- package/dist/database/run-ast/run-ast.js +2 -1
- package/dist/database/run-ast/utils/get-column.js +2 -1
- package/dist/extensions/lib/installation/manager.js +3 -3
- package/dist/extensions/lib/sandbox/register/operation.js +1 -1
- package/dist/extensions/lib/sync/sync.js +2 -2
- package/dist/extensions/manager.js +5 -5
- package/dist/flows.js +12 -10
- package/dist/license/entitlements/lib/collections.js +37 -0
- package/dist/license/entitlements/lib/custom-llms-enabled.js +18 -0
- package/dist/license/entitlements/lib/custom-permission-rules-enabled.js +41 -0
- package/dist/license/entitlements/lib/flows.js +29 -0
- package/dist/license/entitlements/lib/seats.js +103 -0
- package/dist/license/entitlements/lib/sso-enabled.js +45 -0
- package/dist/license/entitlements/manager.js +256 -0
- package/dist/license/index.js +4 -0
- package/dist/license/manager.js +505 -0
- package/dist/license/utils/compute-license-status.js +27 -0
- package/dist/license/utils/get-core-grace-expires-at.js +38 -0
- package/dist/license/utils/get-license-key.js +23 -0
- package/dist/license/utils/get-license-token.js +23 -0
- package/dist/license/utils/handle-license-error.js +41 -0
- package/dist/license/utils/is-in-core-grace-period.js +11 -0
- package/dist/license/utils/is-sso-bypass-allowed.js +21 -0
- package/dist/license/utils/use-rpc.js +33 -0
- package/dist/middleware/cache.js +4 -1
- package/dist/middleware/error-handler.js +11 -0
- package/dist/middleware/extract-token.js +11 -2
- package/dist/middleware/is-admin.js +16 -0
- package/dist/middleware/is-locked.js +16 -0
- package/dist/middleware/mcp-oauth-guard.js +23 -0
- package/dist/middleware/request-counter.js +5 -2
- package/dist/packages/types/dist/index.js +117 -122
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +10 -1
- package/dist/permissions/utils/get-unaliased-field-key.js +2 -1
- package/dist/request/is-denied-ip.js +2 -0
- package/dist/schedules/license.js +31 -0
- package/dist/schedules/oauth-cleanup.js +26 -0
- package/dist/schedules/retention.js +1 -1
- package/dist/schedules/telemetry.js +4 -1
- package/dist/schedules/tus.js +1 -1
- package/dist/schedules/utils/duration-to-cron.js +36 -0
- package/dist/services/activity.js +15 -0
- package/dist/services/authentication.js +12 -5
- package/dist/services/collections.js +41 -10
- package/dist/services/fields.js +6 -6
- package/dist/services/flows.js +12 -0
- package/dist/services/graphql/resolvers/system-admin.js +2 -2
- package/dist/services/graphql/resolvers/system-global.js +1 -1
- package/dist/services/graphql/resolvers/system.js +34 -18
- package/dist/services/graphql/schema/get-types.js +23 -2
- package/dist/services/graphql/schema/parse-query.js +8 -0
- package/dist/services/graphql/schema/read.js +12 -0
- package/dist/services/graphql/types/json-filter.js +30 -0
- package/dist/services/index.js +6 -6
- package/dist/services/items.js +32 -14
- package/dist/services/mcp-oauth/cimd.js +307 -0
- package/dist/services/mcp-oauth/index.js +1185 -0
- package/dist/services/mcp-oauth/types/error.js +22 -0
- package/dist/services/mcp-oauth/utils/cimd-egress.js +182 -0
- package/dist/services/mcp-oauth/utils/domain.js +21 -0
- package/dist/services/mcp-oauth/utils/loopback.js +11 -0
- package/dist/services/mcp-oauth/utils/redirect.js +84 -0
- package/dist/services/mcp-oauth/utils/registration-debug.js +131 -0
- package/dist/services/payload.js +2 -1
- package/dist/services/permissions.js +31 -9
- package/dist/services/revisions.js +15 -0
- package/dist/services/schema.js +2 -2
- package/dist/services/server.js +21 -4
- package/dist/services/settings.js +37 -3
- package/dist/services/users.js +13 -6
- package/dist/services/utils.js +6 -1
- package/dist/services/versions.js +138 -69
- package/dist/utils/calculate-field-depth.js +1 -0
- package/dist/utils/deep-freeze.js +24 -0
- package/dist/utils/extract-function-name.js +13 -0
- package/dist/utils/generate-translations.js +5 -5
- package/dist/utils/get-accountability-for-token.js +13 -1
- package/dist/utils/get-cache-key.js +1 -1
- package/dist/utils/get-history-filter-query.js +22 -0
- package/dist/utils/get-schema.js +2 -2
- package/dist/utils/get-service.js +3 -3
- package/dist/utils/is-admin.js +9 -0
- package/dist/utils/parse-oauth-scope.js +12 -0
- package/dist/utils/sanitize-query.js +1 -1
- package/dist/utils/split-field-path.js +29 -0
- package/dist/utils/transaction.js +2 -2
- package/dist/utils/translations-validation.js +2 -2
- package/dist/utils/validate-diff.js +7 -3
- package/dist/utils/validate-query.js +35 -4
- package/dist/utils/validate-user-count-integrity.js +28 -5
- package/dist/utils/verify-session-jwt.js +5 -2
- package/dist/utils/versioning/handle-version.js +130 -48
- package/dist/utils/versioning/remove-circular.js +17 -0
- package/dist/websocket/authenticate.js +2 -1
- package/dist/websocket/collab/collab.js +1 -1
- package/dist/websocket/collab/room.js +1 -1
- package/dist/websocket/controllers/base.js +12 -0
- package/dist/websocket/controllers/graphql.js +1 -1
- package/dist/websocket/handlers/subscribe.js +1 -1
- package/dist/websocket/messages.js +64 -64
- package/dist/websocket/utils/items.js +2 -2
- package/license +90 -80
- package/package.json +33 -33
- package/dist/controllers/mcp.js +0 -31
- package/dist/utils/job-queue.js +0 -24
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { getOperation } from "../get-operation.js";
|
|
2
|
+
import { parseJsonPath } from "../../../../helpers/fn/json/parse-function.js";
|
|
1
3
|
import { getColumn } from "../../../utils/get-column.js";
|
|
2
|
-
import { getHelpers } from "../../../../helpers/index.js";
|
|
4
|
+
import { getFunctions, getHelpers } from "../../../../helpers/index.js";
|
|
3
5
|
import { InvalidQueryError } from "@directus/errors";
|
|
4
6
|
import { getOutputTypeForFunction } from "@directus/utils";
|
|
5
7
|
|
|
@@ -14,9 +16,51 @@ function castToNumber(value) {
|
|
|
14
16
|
if (Number.isNaN(num)) throw new InvalidQueryError({ reason: `Invalid numeric value` });
|
|
15
17
|
return num;
|
|
16
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Splits "table.column" into ["table", "column"], respecting dots inside parentheses.
|
|
21
|
+
* Handles keys like "table.json(col,path.with.dots)" correctly.
|
|
22
|
+
*/
|
|
23
|
+
function splitTableColumn(key) {
|
|
24
|
+
let depth = 0;
|
|
25
|
+
for (let i = 0; i < key.length; i++) if (key[i] === "(") depth++;
|
|
26
|
+
else if (key[i] === ")") depth--;
|
|
27
|
+
else if (key[i] === "." && depth === 0) return [key.substring(0, i), key.substring(i + 1)];
|
|
28
|
+
return ["", key];
|
|
29
|
+
}
|
|
17
30
|
function applyOperator(knex, dbQuery, schema, key, operator, compareValue, logical = "and", originalCollectionName) {
|
|
18
31
|
const helpers = getHelpers(knex);
|
|
19
|
-
const [table, column] = key
|
|
32
|
+
const [table, column] = splitTableColumn(key);
|
|
33
|
+
if (operator === "_json") {
|
|
34
|
+
if (!Object.entries(compareValue).length) return;
|
|
35
|
+
const applyJsonConditions = (group, filterObj, innerLogical) => {
|
|
36
|
+
for (const [jsonPath, innerFilter] of Object.entries(filterObj)) {
|
|
37
|
+
if (jsonPath === "_or" || jsonPath === "_and") {
|
|
38
|
+
const subLogical = jsonPath === "_or" ? "or" : "and";
|
|
39
|
+
group[innerLogical].where((subGroup) => {
|
|
40
|
+
for (const subFilter of innerFilter) applyJsonConditions(subGroup, subFilter, subLogical);
|
|
41
|
+
});
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const normalizedPath = parseJsonPath(jsonPath);
|
|
45
|
+
const innerValue = innerFilter[Object.keys(innerFilter)[0]];
|
|
46
|
+
const castNumeric = typeof innerValue === "number" || Array.isArray(innerValue) && innerValue.length > 0 && typeof innerValue[0] === "number";
|
|
47
|
+
const jsonExtractionRaw = getFunctions(knex, schema).json(table, column, {
|
|
48
|
+
type: "json",
|
|
49
|
+
jsonPath: normalizedPath,
|
|
50
|
+
originalCollectionName,
|
|
51
|
+
relationalCountOptions: void 0,
|
|
52
|
+
jsonReturnType: castNumeric ? "numeric" : "text"
|
|
53
|
+
});
|
|
54
|
+
const innerOp = getOperation(Object.keys(innerFilter)[0], Object.values(innerFilter)[0]);
|
|
55
|
+
if (!innerOp) continue;
|
|
56
|
+
applyOperatorToRaw(group, helpers, jsonExtractionRaw, innerOp.operator, innerOp.value, innerLogical);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
dbQuery[logical].where((group) => {
|
|
60
|
+
applyJsonConditions(group, compareValue, "and");
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
20
64
|
const selectionRaw = getColumn(knex, table, column, false, schema, { originalCollectionName });
|
|
21
65
|
if (operator === "_null" && compareValue !== false || operator === "_nnull" && compareValue === false || operator === "_eq" && compareValue === null) {
|
|
22
66
|
dbQuery[logical].whereNull(selectionRaw);
|
|
@@ -26,12 +70,18 @@ function applyOperator(knex, dbQuery, schema, key, operator, compareValue, logic
|
|
|
26
70
|
dbQuery[logical].whereNotNull(selectionRaw);
|
|
27
71
|
return;
|
|
28
72
|
}
|
|
29
|
-
if (operator === "_empty" && compareValue !== false || operator === "_nempty" && compareValue === false)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
73
|
+
if (operator === "_empty" && compareValue !== false || operator === "_nempty" && compareValue === false) {
|
|
74
|
+
dbQuery[logical].andWhere((query) => {
|
|
75
|
+
query.whereNull(selectionRaw).orWhere(selectionRaw, "=", "");
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (operator === "_nempty" && compareValue !== false || operator === "_empty" && compareValue === false) {
|
|
80
|
+
dbQuery[logical].andWhere((query) => {
|
|
81
|
+
query.whereNotNull(selectionRaw).andWhere(selectionRaw, "!=", "");
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
35
85
|
if (compareValue === void 0) return;
|
|
36
86
|
if (Array.isArray(compareValue)) compareValue = compareValue.filter((val) => val !== void 0);
|
|
37
87
|
if (column.includes("(") && column.includes(")")) {
|
|
@@ -43,7 +93,7 @@ function applyOperator(knex, dbQuery, schema, key, operator, compareValue, logic
|
|
|
43
93
|
"decimal"
|
|
44
94
|
].includes(type)) compareValue = castToNumber(compareValue);
|
|
45
95
|
}
|
|
46
|
-
const [collection, field] = key
|
|
96
|
+
const [collection, field] = splitTableColumn(key);
|
|
47
97
|
const mappedCollection = originalCollectionName || collection;
|
|
48
98
|
if (mappedCollection in schema.collections && field in schema.collections[mappedCollection].fields) {
|
|
49
99
|
const type = schema.collections[mappedCollection].fields[field].type;
|
|
@@ -60,47 +110,80 @@ function applyOperator(knex, dbQuery, schema, key, operator, compareValue, logic
|
|
|
60
110
|
"decimal"
|
|
61
111
|
].includes(type)) compareValue = castToNumber(compareValue);
|
|
62
112
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (operator === "
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (operator === "
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (operator === "
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (operator === "
|
|
81
|
-
|
|
82
|
-
|
|
113
|
+
applyOperatorToRaw(dbQuery, helpers, selectionRaw, operator, compareValue, logical, key);
|
|
114
|
+
}
|
|
115
|
+
function applyOperatorToRaw(dbQuery, helpers, raw, operator, compareValue, logical, key) {
|
|
116
|
+
if (operator === "_null" && compareValue !== false || operator === "_nnull" && compareValue === false || operator === "_eq" && compareValue === null) {
|
|
117
|
+
dbQuery[logical].whereNull(raw);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (operator === "_nnull" && compareValue !== false || operator === "_null" && compareValue === false || operator === "_neq" && compareValue === null) {
|
|
121
|
+
dbQuery[logical].whereNotNull(raw);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (operator === "_empty" && compareValue !== false || operator === "_nempty" && compareValue === false) {
|
|
125
|
+
dbQuery[logical].andWhere((query) => {
|
|
126
|
+
query.whereNull(raw).orWhere(raw, "=", "");
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (operator === "_nempty" && compareValue !== false || operator === "_empty" && compareValue === false) {
|
|
131
|
+
dbQuery[logical].andWhere((query) => {
|
|
132
|
+
query.whereNotNull(raw).andWhere(raw, "!=", "");
|
|
133
|
+
});
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (compareValue === void 0) return;
|
|
137
|
+
if (Array.isArray(compareValue)) compareValue = compareValue.filter((val) => val !== void 0);
|
|
138
|
+
if (operator === "_eq") dbQuery[logical].where(raw, "=", compareValue);
|
|
139
|
+
if (operator === "_neq") dbQuery[logical].whereNot(raw, compareValue);
|
|
140
|
+
if (operator === "_ieq") dbQuery[logical].whereRaw(`LOWER(??) = ?`, [raw, `${compareValue.toLowerCase()}`]);
|
|
141
|
+
if (operator === "_nieq") dbQuery[logical].whereRaw(`LOWER(??) <> ?`, [raw, `${compareValue.toLowerCase()}`]);
|
|
142
|
+
if (operator === "_contains") dbQuery[logical].where(raw, "like", `%${compareValue}%`);
|
|
143
|
+
if (operator === "_ncontains") dbQuery[logical].whereNot(raw, "like", `%${compareValue}%`);
|
|
144
|
+
if (operator === "_icontains") dbQuery[logical].whereRaw(`LOWER(??) LIKE ?`, [raw, `%${compareValue.toLowerCase()}%`]);
|
|
145
|
+
if (operator === "_nicontains") dbQuery[logical].whereRaw(`LOWER(??) NOT LIKE ?`, [raw, `%${compareValue.toLowerCase()}%`]);
|
|
146
|
+
if (operator === "_starts_with") dbQuery[logical].where(raw, "like", `${compareValue}%`);
|
|
147
|
+
if (operator === "_nstarts_with") dbQuery[logical].whereNot(raw, "like", `${compareValue}%`);
|
|
148
|
+
if (operator === "_istarts_with") dbQuery[logical].whereRaw(`LOWER(??) LIKE ?`, [raw, `${compareValue.toLowerCase()}%`]);
|
|
149
|
+
if (operator === "_nistarts_with") dbQuery[logical].whereRaw(`LOWER(??) NOT LIKE ?`, [raw, `${compareValue.toLowerCase()}%`]);
|
|
150
|
+
if (operator === "_ends_with") dbQuery[logical].where(raw, "like", `%${compareValue}`);
|
|
151
|
+
if (operator === "_nends_with") dbQuery[logical].whereNot(raw, "like", `%${compareValue}`);
|
|
152
|
+
if (operator === "_iends_with") dbQuery[logical].whereRaw(`LOWER(??) LIKE ?`, [raw, `%${compareValue.toLowerCase()}`]);
|
|
153
|
+
if (operator === "_niends_with") dbQuery[logical].whereRaw(`LOWER(??) NOT LIKE ?`, [raw, `%${compareValue.toLowerCase()}`]);
|
|
154
|
+
if (operator === "_gt") dbQuery[logical].where(raw, ">", compareValue);
|
|
155
|
+
if (operator === "_gte") dbQuery[logical].where(raw, ">=", compareValue);
|
|
156
|
+
if (operator === "_lt") dbQuery[logical].where(raw, "<", compareValue);
|
|
157
|
+
if (operator === "_lte") dbQuery[logical].where(raw, "<=", compareValue);
|
|
83
158
|
if (operator === "_in") {
|
|
84
159
|
let value = compareValue;
|
|
85
160
|
if (typeof value === "string") value = value.split(",");
|
|
86
|
-
dbQuery[logical].whereIn(
|
|
161
|
+
if (value.length === 0) dbQuery[logical].whereIn(raw, []);
|
|
162
|
+
else {
|
|
163
|
+
const placeholders = value.map(() => "?").join(", ");
|
|
164
|
+
dbQuery[logical].whereRaw(`?? in (${placeholders})`, [raw, ...value]);
|
|
165
|
+
}
|
|
87
166
|
}
|
|
88
167
|
if (operator === "_nin") {
|
|
89
168
|
let value = compareValue;
|
|
90
169
|
if (typeof value === "string") value = value.split(",");
|
|
91
|
-
dbQuery[logical].whereNotIn(
|
|
170
|
+
if (value.length === 0) dbQuery[logical].whereNotIn(raw, []);
|
|
171
|
+
else {
|
|
172
|
+
const placeholders = value.map(() => "?").join(", ");
|
|
173
|
+
dbQuery[logical].whereRaw(`?? not in (${placeholders})`, [raw, ...value]);
|
|
174
|
+
}
|
|
92
175
|
}
|
|
93
176
|
if (operator === "_between") {
|
|
94
177
|
let value = compareValue;
|
|
95
178
|
if (typeof value === "string") value = value.split(",");
|
|
96
179
|
if (value.length !== 2) return;
|
|
97
|
-
dbQuery[logical].whereBetween(
|
|
180
|
+
dbQuery[logical].whereBetween(raw, value);
|
|
98
181
|
}
|
|
99
182
|
if (operator === "_nbetween") {
|
|
100
183
|
let value = compareValue;
|
|
101
184
|
if (typeof value === "string") value = value.split(",");
|
|
102
185
|
if (value.length !== 2) return;
|
|
103
|
-
dbQuery[logical].whereNotBetween(
|
|
186
|
+
dbQuery[logical].whereNotBetween(raw, value);
|
|
104
187
|
}
|
|
105
188
|
if (operator == "_intersects") dbQuery[logical].whereRaw(helpers.st.intersects(key, compareValue));
|
|
106
189
|
if (operator == "_nintersects") dbQuery[logical].whereRaw(helpers.st.nintersects(key, compareValue));
|
|
@@ -20,7 +20,10 @@ function applyQuery(knex, collection, dbQuery, query, schema, cases, permissions
|
|
|
20
20
|
if (query.offset) applyOffset(knex, dbQuery, query.offset);
|
|
21
21
|
if (query.page && query.limit && query.limit !== -1) applyOffset(knex, dbQuery, query.limit * (query.page - 1));
|
|
22
22
|
if (query.sort && !options?.isInnerQuery && !options?.hasMultiRelationalSort) {
|
|
23
|
-
const sortResult = applySort(knex, schema, dbQuery, query.sort,
|
|
23
|
+
const sortResult = applySort(knex, schema, dbQuery, query.sort, collection, aliasMap, {
|
|
24
|
+
aggregate: query.aggregate,
|
|
25
|
+
fieldAliasMap: { ...query.alias ?? {} }
|
|
26
|
+
});
|
|
24
27
|
if (!hasJoins) hasJoins = sortResult.hasJoins;
|
|
25
28
|
}
|
|
26
29
|
const filter = joinFilterWithCases(query.filter, cases);
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { getColumnPath } from "../../../../utils/get-column-path.js";
|
|
2
2
|
import { addJoin } from "./add-join.js";
|
|
3
3
|
import { getColumn } from "../../utils/get-column.js";
|
|
4
|
+
import { extractFunctionName } from "../../../../utils/extract-function-name.js";
|
|
5
|
+
import { splitFieldPath } from "../../../../utils/split-field-path.js";
|
|
4
6
|
import { getRelationInfo } from "@directus/utils";
|
|
5
7
|
|
|
6
8
|
//#region src/database/run-ast/lib/apply-query/sort.ts
|
|
7
|
-
function applySort(knex, schema, rootQuery, sort,
|
|
9
|
+
function applySort(knex, schema, rootQuery, sort, collection, aliasMap, options) {
|
|
10
|
+
const { aggregate, returnRecords = false, fieldAliasMap } = options ?? {};
|
|
8
11
|
const relations = schema.relations;
|
|
9
12
|
let hasJoins = false;
|
|
10
13
|
let hasMultiRelationalSort = false;
|
|
11
14
|
const sortRecords = sort.map((sortField) => {
|
|
12
|
-
const column = sortField
|
|
15
|
+
const column = splitFieldPath(sortField);
|
|
13
16
|
let order = "asc";
|
|
14
17
|
if (sortField.startsWith("-")) order = "desc";
|
|
15
18
|
if (column[0].startsWith("-")) column[0] = column[0].substring(1);
|
|
@@ -30,11 +33,17 @@ function applySort(knex, schema, rootQuery, sort, aggregate, collection, aliasMa
|
|
|
30
33
|
};
|
|
31
34
|
}
|
|
32
35
|
if (column.length === 1) {
|
|
33
|
-
const
|
|
36
|
+
const rawField = column[0];
|
|
37
|
+
const resolvedField = fieldAliasMap?.[rawField] ?? rawField;
|
|
38
|
+
if (extractFunctionName(resolvedField) === "json") return {
|
|
39
|
+
order,
|
|
40
|
+
column: returnRecords ? resolvedField : getColumn(knex, collection, resolvedField, false, schema, { jsonReturnType: "text" })
|
|
41
|
+
};
|
|
42
|
+
const pathRoot = resolvedField.split(":")[0];
|
|
34
43
|
const { relation, relationType } = getRelationInfo(relations, collection, pathRoot);
|
|
35
44
|
if (!relation || ["m2o", "a2o"].includes(relationType ?? "")) return {
|
|
36
45
|
order,
|
|
37
|
-
column: returnRecords ?
|
|
46
|
+
column: returnRecords ? resolvedField : getColumn(knex, collection, resolvedField, false, schema)
|
|
38
47
|
};
|
|
39
48
|
}
|
|
40
49
|
const { hasMultiRelational, isJoinAdded } = addJoin({
|
|
@@ -45,19 +54,20 @@ function applySort(knex, schema, rootQuery, sort, aggregate, collection, aliasMa
|
|
|
45
54
|
schema,
|
|
46
55
|
knex
|
|
47
56
|
});
|
|
48
|
-
const { columnPath } = getColumnPath({
|
|
57
|
+
const { columnPath, targetCollection } = getColumnPath({
|
|
49
58
|
path: column,
|
|
50
59
|
collection,
|
|
51
60
|
aliasMap,
|
|
52
61
|
relations,
|
|
53
62
|
schema
|
|
54
63
|
});
|
|
55
|
-
const [alias,
|
|
64
|
+
const [alias, ...rest] = splitFieldPath(columnPath);
|
|
65
|
+
const field = rest.join(".");
|
|
56
66
|
if (!hasJoins) hasJoins = isJoinAdded;
|
|
57
67
|
if (!hasMultiRelationalSort) hasMultiRelationalSort = hasMultiRelational;
|
|
58
68
|
return {
|
|
59
69
|
order,
|
|
60
|
-
column: returnRecords ? columnPath : getColumn(knex, alias, field, false, schema)
|
|
70
|
+
column: returnRecords ? columnPath : getColumn(knex, alias, field, false, schema, { originalCollectionName: targetCollection })
|
|
61
71
|
};
|
|
62
72
|
});
|
|
63
73
|
if (returnRecords) return {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { generateQueryAlias } from "../utils/generate-alias.js";
|
|
2
2
|
import { applyCaseWhen } from "../utils/apply-case-when.js";
|
|
3
|
+
import { applyFunctionToColumnName } from "../utils/apply-function-to-column-name.js";
|
|
3
4
|
import { getColumn } from "../utils/get-column.js";
|
|
4
5
|
import { applyLimit } from "./apply-query/pagination.js";
|
|
6
|
+
import { extractFunctionName } from "../../../utils/extract-function-name.js";
|
|
7
|
+
import { splitFieldPath } from "../../../utils/split-field-path.js";
|
|
5
8
|
import { applySort } from "./apply-query/sort.js";
|
|
6
9
|
import applyQuery from "./apply-query/index.js";
|
|
7
10
|
import { getHelpers } from "../../helpers/index.js";
|
|
@@ -43,7 +46,13 @@ function getDBQuery({ table, fieldNodes, o2mNodes, query, cases, permissions, pe
|
|
|
43
46
|
const innerQuerySortRecords = [];
|
|
44
47
|
let hasMultiRelationalSort;
|
|
45
48
|
if (queryCopy.sort) {
|
|
46
|
-
const
|
|
49
|
+
const fieldAliasMap = { ...queryCopy.alias ?? {} };
|
|
50
|
+
for (const node of fieldNodes) if (node.type === "functionField" && extractFunctionName(node.name) === "json") fieldAliasMap[applyFunctionToColumnName(node.fieldKey)] = node.name;
|
|
51
|
+
const sortResult = applySort(knex, schema, dbQuery, queryCopy.sort, table, aliasMap, {
|
|
52
|
+
aggregate: queryCopy.aggregate,
|
|
53
|
+
returnRecords: true,
|
|
54
|
+
fieldAliasMap
|
|
55
|
+
});
|
|
47
56
|
if (sortResult) {
|
|
48
57
|
sortRecords = sortResult.sortRecords;
|
|
49
58
|
hasMultiRelationalSort = sortResult.hasMultiRelationalSort;
|
|
@@ -85,16 +94,18 @@ function getDBQuery({ table, fieldNodes, o2mNodes, query, cases, permissions, pe
|
|
|
85
94
|
if (orderByString.length !== 0) orderByString += ", ";
|
|
86
95
|
const sortAlias = generateQueryAlias(table, queryCopy, `sort_${index}_${sortRecord.column}_${sortRecord.order}`);
|
|
87
96
|
let orderByColumn;
|
|
88
|
-
|
|
89
|
-
|
|
97
|
+
const colParts = splitFieldPath(sortRecord.column);
|
|
98
|
+
if (colParts.length > 1) {
|
|
99
|
+
const [alias, ...rest] = colParts;
|
|
100
|
+
const field = rest.join(".");
|
|
90
101
|
const originalCollectionName = getCollectionFromAlias(alias, aliasMap);
|
|
91
102
|
dbQuery.select(getColumn(knex, alias, field, sortAlias, schema, { originalCollectionName }));
|
|
92
103
|
orderByString += `?? ${sortRecord.order}`;
|
|
93
104
|
orderByColumn = getColumn(knex, alias, field, false, schema, { originalCollectionName });
|
|
94
105
|
} else {
|
|
95
|
-
dbQuery.select(getColumn(knex, table, sortRecord.column, sortAlias, schema));
|
|
106
|
+
dbQuery.select(getColumn(knex, table, sortRecord.column, sortAlias, schema, { jsonReturnType: "text" }));
|
|
96
107
|
orderByString += `?? ${sortRecord.order}`;
|
|
97
|
-
orderByColumn = getColumn(knex, table, sortRecord.column, false, schema);
|
|
108
|
+
orderByColumn = getColumn(knex, table, sortRecord.column, false, schema, { jsonReturnType: "text" });
|
|
98
109
|
}
|
|
99
110
|
orderByFields.push(orderByColumn);
|
|
100
111
|
innerQuerySortRecords.push({
|
|
@@ -111,10 +122,11 @@ function getDBQuery({ table, fieldNodes, o2mNodes, query, cases, permissions, pe
|
|
|
111
122
|
dbQuery.orderByRaw(orderByString, orderByFields);
|
|
112
123
|
} else {
|
|
113
124
|
sortRecords.map((sortRecord) => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
const colParts = splitFieldPath(sortRecord.column);
|
|
126
|
+
if (colParts.length > 1) {
|
|
127
|
+
const [alias, ...rest] = colParts;
|
|
128
|
+
sortRecord.column = getColumn(knex, alias, rest.join("."), false, schema, { originalCollectionName: getCollectionFromAlias(alias, aliasMap) });
|
|
129
|
+
} else sortRecord.column = getColumn(knex, table, sortRecord.column, false, schema, { jsonReturnType: "text" });
|
|
118
130
|
});
|
|
119
131
|
dbQuery.orderBy(sortRecords);
|
|
120
132
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseJsonFunction } from "../../helpers/fn/json/parse-function.js";
|
|
2
|
+
import { extractFunctionName } from "../../../utils/extract-function-name.js";
|
|
2
3
|
import { parseFilterKey } from "../../../utils/parse-filter-key.js";
|
|
3
4
|
|
|
4
5
|
//#region src/database/run-ast/lib/parse-current-level.ts
|
|
@@ -10,7 +11,7 @@ async function parseCurrentLevel(schema, collection, children, query) {
|
|
|
10
11
|
for (const child of children) {
|
|
11
12
|
if (child.type === "field" || child.type === "functionField") {
|
|
12
13
|
let fieldName;
|
|
13
|
-
if (child.type
|
|
14
|
+
if (child.type === "functionField" && extractFunctionName(child.name) === "json") fieldName = parseJsonFunction(child.name).field;
|
|
14
15
|
else fieldName = parseFilterKey(child.name).fieldName;
|
|
15
16
|
if (columnsInCollection.includes(fieldName)) columnsToSelectInternal.push(child.fieldKey);
|
|
16
17
|
continue;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { applyFunctionToColumnName } from "./utils/apply-function-to-column-name.js";
|
|
2
|
+
import { extractFunctionName } from "../../utils/extract-function-name.js";
|
|
2
3
|
import database_default from "../index.js";
|
|
3
4
|
import { fetchPolicies } from "../../permissions/lib/fetch-policies.js";
|
|
4
5
|
import { fetchPermissions } from "../../permissions/lib/fetch-permissions.js";
|
|
@@ -57,7 +58,7 @@ async function runAst(originalAST, schema, accountability, options) {
|
|
|
57
58
|
schema
|
|
58
59
|
});
|
|
59
60
|
const aliasMap = { ...query.alias };
|
|
60
|
-
for (const child of children) if (child.type === "functionField" && child.name
|
|
61
|
+
for (const child of children) if (child.type === "functionField" && extractFunctionName(child.name) === "json") {
|
|
61
62
|
const alias = applyFunctionToColumnName(child.fieldKey);
|
|
62
63
|
aliasMap[alias] = child.name;
|
|
63
64
|
}
|
|
@@ -42,7 +42,8 @@ function getColumn(knex, table, column, alias = applyFunctionToColumnName(column
|
|
|
42
42
|
permissions: options.permissions
|
|
43
43
|
} : void 0,
|
|
44
44
|
originalCollectionName: options?.originalCollectionName,
|
|
45
|
-
jsonPath
|
|
45
|
+
jsonPath,
|
|
46
|
+
...options?.jsonReturnType && { jsonReturnType: options.jsonReturnType }
|
|
46
47
|
});
|
|
47
48
|
if (alias) return knex.raw(result + " AS ??", [alias]);
|
|
48
49
|
return result;
|
|
@@ -10,7 +10,7 @@ import { Readable } from "node:stream";
|
|
|
10
10
|
import { download } from "@directus/extensions-registry";
|
|
11
11
|
import { EXTENSION_PKG_KEY, ExtensionManifest } from "@directus/extensions";
|
|
12
12
|
import DriverLocal from "@directus/storage-driver-local";
|
|
13
|
-
import
|
|
13
|
+
import PQueue from "p-queue";
|
|
14
14
|
import { extract } from "tar";
|
|
15
15
|
|
|
16
16
|
//#region src/extensions/lib/installation/manager.ts
|
|
@@ -50,7 +50,7 @@ var InstallationManager = class {
|
|
|
50
50
|
if (!(await ExtensionManifest.parseAsync(packageFile))[EXTENSION_PKG_KEY]?.type) throw new Error(`Extension type not found in package.json`);
|
|
51
51
|
if (env["EXTENSIONS_LOCATION"]) {
|
|
52
52
|
const remoteDisk = (await getStorage()).location(env["EXTENSIONS_LOCATION"]);
|
|
53
|
-
const queue = new
|
|
53
|
+
const queue = new PQueue({ concurrency: 1e3 });
|
|
54
54
|
for await (const filepath of tmpStorage.list(extractedPath)) {
|
|
55
55
|
const readStream = await tmpStorage.read(filepath);
|
|
56
56
|
const remotePath = join(env["EXTENSIONS_PATH"], ".registry", versionId, filepath.substring(7));
|
|
@@ -74,7 +74,7 @@ var InstallationManager = class {
|
|
|
74
74
|
async uninstall(folder) {
|
|
75
75
|
if (env["EXTENSIONS_LOCATION"]) {
|
|
76
76
|
const remoteDisk = (await getStorage()).location(env["EXTENSIONS_LOCATION"]);
|
|
77
|
-
const queue = new
|
|
77
|
+
const queue = new PQueue({ concurrency: 1e3 });
|
|
78
78
|
const prefix = join(env["EXTENSIONS_PATH"], ".registry", folder);
|
|
79
79
|
for await (const filepath of remoteDisk.list(prefix)) queue.add(() => remoteDisk.delete(filepath));
|
|
80
80
|
await queue.onIdle();
|
|
@@ -14,7 +14,7 @@ import { normalizePath } from "@directus/utils";
|
|
|
14
14
|
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
15
15
|
import { pipeline } from "node:stream/promises";
|
|
16
16
|
import { createWriteStream } from "node:fs";
|
|
17
|
-
import
|
|
17
|
+
import PQueue from "p-queue";
|
|
18
18
|
import mid from "node-machine-id";
|
|
19
19
|
|
|
20
20
|
//#region src/extensions/lib/sync/sync.ts
|
|
@@ -50,7 +50,7 @@ async function syncExtensions(options) {
|
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
const queue = new
|
|
53
|
+
const queue = new PQueue({ concurrency: 1e3 });
|
|
54
54
|
const fileTracker = new SyncFileTracker();
|
|
55
55
|
const hasLocalFiles = await fileTracker.readLocalFiles(localExtensionsPath) > 0;
|
|
56
56
|
for await (const filepath of disk.list(remoteExtensionsPath)) {
|
|
@@ -4,12 +4,12 @@ import { useLogger } from "../logger/index.js";
|
|
|
4
4
|
import { getExtensionsPath } from "./lib/get-extensions-path.js";
|
|
5
5
|
import database_default from "../database/index.js";
|
|
6
6
|
import emitter_default, { Emitter } from "../emitter.js";
|
|
7
|
+
import { scheduleSynchronizedJob, validateCron } from "../utils/schedule.js";
|
|
7
8
|
import { getSchema } from "../utils/get-schema.js";
|
|
9
|
+
import { getFlowManager } from "../flows.js";
|
|
8
10
|
import { deleteFromRequireCache } from "../utils/delete-from-require-cache.js";
|
|
9
11
|
import getModuleDefault from "../utils/get-module-default.js";
|
|
10
12
|
import { importFileUrl } from "../utils/import-file-url.js";
|
|
11
|
-
import { JobQueue } from "../utils/job-queue.js";
|
|
12
|
-
import { scheduleSynchronizedJob, validateCron } from "../utils/schedule.js";
|
|
13
13
|
import { getExtensionsSettings } from "./lib/get-extensions-settings.js";
|
|
14
14
|
import { getExtensions } from "./lib/get-extensions.js";
|
|
15
15
|
import { getSharedDepsMapping } from "./lib/get-shared-deps-mapping.js";
|
|
@@ -19,7 +19,6 @@ import { instantiateSandboxSdk } from "./lib/sandbox/sdk/instantiate.js";
|
|
|
19
19
|
import { syncExtensions } from "./lib/sync/sync.js";
|
|
20
20
|
import { wrapEmbeds } from "./lib/wrap-embeds.js";
|
|
21
21
|
import { services_exports } from "../services/index.js";
|
|
22
|
-
import { getFlowManager } from "../flows.js";
|
|
23
22
|
import { readFile, readdir } from "node:fs/promises";
|
|
24
23
|
import path from "path";
|
|
25
24
|
import { useEnv } from "@directus/env";
|
|
@@ -39,6 +38,7 @@ import nodeResolveDefault from "@rollup/plugin-node-resolve";
|
|
|
39
38
|
import virtualDefault from "@rollup/plugin-virtual";
|
|
40
39
|
import chokidar from "chokidar";
|
|
41
40
|
import ivm from "isolated-vm";
|
|
41
|
+
import PQueue from "p-queue";
|
|
42
42
|
import { rolldown } from "rolldown";
|
|
43
43
|
import { rollup } from "rollup";
|
|
44
44
|
|
|
@@ -97,7 +97,7 @@ var ExtensionManager = class {
|
|
|
97
97
|
* Used to prevent race conditions when reloading extensions. Forces each reload to happen in
|
|
98
98
|
* sequence.
|
|
99
99
|
*/
|
|
100
|
-
reloadQueue = new
|
|
100
|
+
reloadQueue = new PQueue({ concurrency: 1 });
|
|
101
101
|
/**
|
|
102
102
|
* Used to prevent race condition when reading extension data while reloading extensions
|
|
103
103
|
*/
|
|
@@ -248,7 +248,7 @@ var ExtensionManager = class {
|
|
|
248
248
|
resolve$1 = res;
|
|
249
249
|
reject = rej;
|
|
250
250
|
});
|
|
251
|
-
this.reloadQueue.
|
|
251
|
+
this.reloadQueue.add(async () => {
|
|
252
252
|
if (this.isLoaded) {
|
|
253
253
|
const prevExtensions = clone(this.extensions);
|
|
254
254
|
await this.unload();
|
package/dist/flows.js
CHANGED
|
@@ -5,22 +5,22 @@ import database_default from "./database/index.js";
|
|
|
5
5
|
import { fetchPolicies } from "./permissions/lib/fetch-policies.js";
|
|
6
6
|
import { fetchPermissions } from "./permissions/lib/fetch-permissions.js";
|
|
7
7
|
import emitter_default from "./emitter.js";
|
|
8
|
-
import {
|
|
8
|
+
import { scheduleSynchronizedJob, validateCron } from "./utils/schedule.js";
|
|
9
9
|
import { ActivityService } from "./services/activity.js";
|
|
10
10
|
import { getService } from "./utils/get-service.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { getSchema } from "./utils/get-schema.js";
|
|
12
|
+
import { FlowsService } from "./services/flows.js";
|
|
13
13
|
import { RevisionsService } from "./services/revisions.js";
|
|
14
|
-
import { services_exports } from "./services/index.js";
|
|
15
14
|
import { constructFlowTree } from "./utils/construct-flow-tree.js";
|
|
16
15
|
import { redactObject } from "./utils/redact-object.js";
|
|
17
|
-
import {
|
|
16
|
+
import { services_exports } from "./services/index.js";
|
|
18
17
|
import { useEnv } from "@directus/env";
|
|
19
18
|
import { ForbiddenError } from "@directus/errors";
|
|
20
19
|
import { applyOptionsData, deepMap, getRedactedString, isValidJSON, parseJSON, toArray } from "@directus/utils";
|
|
21
20
|
import { pick } from "lodash-es";
|
|
22
21
|
import { Action } from "@directus/constants";
|
|
23
22
|
import { isSystemCollection } from "@directus/system-data";
|
|
23
|
+
import PQueue from "p-queue";
|
|
24
24
|
import { get as get$1 } from "micromustache";
|
|
25
25
|
|
|
26
26
|
//#region src/flows.ts
|
|
@@ -41,15 +41,15 @@ var FlowManager = class {
|
|
|
41
41
|
triggerHandlers = [];
|
|
42
42
|
operationFlowHandlers = {};
|
|
43
43
|
webhookFlowHandlers = {};
|
|
44
|
-
reloadQueue;
|
|
44
|
+
reloadQueue = new PQueue({ concurrency: 1 });
|
|
45
45
|
envs;
|
|
46
46
|
constructor() {
|
|
47
47
|
const env = useEnv();
|
|
48
|
-
const logger = useLogger();
|
|
49
|
-
this.reloadQueue = new JobQueue();
|
|
50
48
|
this.envs = env["FLOWS_ENV_ALLOW_LIST"] ? pick(env, toArray(env["FLOWS_ENV_ALLOW_LIST"])) : {};
|
|
51
|
-
useBus()
|
|
52
|
-
|
|
49
|
+
const messenger = useBus();
|
|
50
|
+
const logger = useLogger();
|
|
51
|
+
messenger.subscribe("flows", (event) => {
|
|
52
|
+
if (event.type === "reload") this.reloadQueue.add(async () => {
|
|
53
53
|
if (this.isLoaded) {
|
|
54
54
|
await this.unload();
|
|
55
55
|
await this.load();
|
|
@@ -70,6 +70,7 @@ var FlowManager = class {
|
|
|
70
70
|
this.operations.delete(id);
|
|
71
71
|
}
|
|
72
72
|
async runOperationFlow(id, data, context) {
|
|
73
|
+
if (this.reloadQueue.pending > 0) await this.reloadQueue.onIdle();
|
|
73
74
|
const logger = useLogger();
|
|
74
75
|
if (!(id in this.operationFlowHandlers)) {
|
|
75
76
|
logger.warn(`Couldn't find operation triggered flow with id "${id}"`);
|
|
@@ -79,6 +80,7 @@ var FlowManager = class {
|
|
|
79
80
|
return handler(data, context);
|
|
80
81
|
}
|
|
81
82
|
async runWebhookFlow(id, data, context) {
|
|
83
|
+
if (this.reloadQueue.pending > 0) await this.reloadQueue.onIdle();
|
|
82
84
|
const logger = useLogger();
|
|
83
85
|
if (!(id in this.webhookFlowHandlers)) {
|
|
84
86
|
logger.warn(`Couldn't find webhook or manual triggered flow with id "${id}"`);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import database_default from "../../../database/index.js";
|
|
2
|
+
import { getSchema } from "../../../utils/get-schema.js";
|
|
3
|
+
import "../../../services/index.js";
|
|
4
|
+
import { CollectionsService } from "../../../services/collections.js";
|
|
5
|
+
import { useEnv } from "@directus/env";
|
|
6
|
+
import { isSystemCollection } from "@directus/system-data";
|
|
7
|
+
|
|
8
|
+
//#region src/license/entitlements/lib/collections.ts
|
|
9
|
+
async function getActiveCollections(opts) {
|
|
10
|
+
const env = useEnv();
|
|
11
|
+
const knex = opts?.knex ?? database_default();
|
|
12
|
+
return (await new CollectionsService({
|
|
13
|
+
schema: await getSchema({ database: knex }),
|
|
14
|
+
knex
|
|
15
|
+
}).readByQuery()).filter((collection) => {
|
|
16
|
+
const isFolder = collection.schema === null;
|
|
17
|
+
const isDBOnly = collection.meta === null;
|
|
18
|
+
const isDisabled = collection.meta?.status !== "active";
|
|
19
|
+
const isEnvExcluded = env["DB_EXCLUDE_TABLES"].includes(collection.collection);
|
|
20
|
+
return !isFolder && !isSystemCollection(collection.collection) && !isDBOnly && !isDisabled && !isEnvExcluded;
|
|
21
|
+
}).map((collection) => collection.collection);
|
|
22
|
+
}
|
|
23
|
+
async function countActiveCollections(opts) {
|
|
24
|
+
return (await getActiveCollections(opts)).length;
|
|
25
|
+
}
|
|
26
|
+
async function resolveCollections(collections, ctx) {
|
|
27
|
+
const collectionsService = new CollectionsService({
|
|
28
|
+
schema: await getSchema(),
|
|
29
|
+
accountability: ctx?.accountability
|
|
30
|
+
});
|
|
31
|
+
await Promise.allSettled(collections.map((collection) => {
|
|
32
|
+
return collectionsService.updateOne(collection, { meta: { status: "inactive" } });
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { countActiveCollections, getActiveCollections, resolveCollections };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CUSTOM_LLM_FIELDS } from "../../../constants.js";
|
|
2
|
+
import database_default from "../../../database/index.js";
|
|
3
|
+
import { getSchema } from "../../../utils/get-schema.js";
|
|
4
|
+
import { SettingsService } from "../../../services/settings.js";
|
|
5
|
+
import "../../../services/index.js";
|
|
6
|
+
|
|
7
|
+
//#region src/license/entitlements/lib/custom-llms-enabled.ts
|
|
8
|
+
async function checkCustomLLM(opts) {
|
|
9
|
+
const knex = opts?.knex ?? database_default();
|
|
10
|
+
const data = await new SettingsService({
|
|
11
|
+
schema: await getSchema({ database: knex }),
|
|
12
|
+
knex
|
|
13
|
+
}).readSingleton({ fields: [...CUSTOM_LLM_FIELDS] });
|
|
14
|
+
return !CUSTOM_LLM_FIELDS.find((key) => data[key] !== null);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { checkCustomLLM };
|