@directus/api 35.0.1 → 35.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "../../../packages/types/dist/index.js";
|
|
2
|
+
import { coerceJsonFields } from "../../tools/utils.js";
|
|
2
3
|
import { ALL_TOOLS } from "../../tools/index.js";
|
|
3
4
|
import { InvalidPayloadError } from "@directus/errors";
|
|
4
5
|
import { jsonSchema, tool, zodSchema } from "ai";
|
|
@@ -19,7 +20,8 @@ const chatRequestToolToAiSdkTool = ({ chatRequestTool, accountability, schema, t
|
|
|
19
20
|
inputSchema,
|
|
20
21
|
needsApproval,
|
|
21
22
|
execute: async (rawArgs) => {
|
|
22
|
-
const
|
|
23
|
+
const coercedArgs = coerceJsonFields(rawArgs);
|
|
24
|
+
const { error, data: args } = directusTool.validateSchema?.safeParse(coercedArgs) ?? { data: coercedArgs };
|
|
23
25
|
if (error) {
|
|
24
26
|
throw new InvalidPayloadError({ reason: fromZodError(error).message });
|
|
25
27
|
}
|
package/dist/ai/mcp/server.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { ItemsService } from "../../services/items.js";
|
|
2
|
+
import { coerceJsonFields } from "../tools/utils.js";
|
|
2
3
|
import { Url } from "../../utils/url.js";
|
|
3
4
|
import "../../services/index.js";
|
|
4
5
|
import { findMcpTool, getAllMcpTools } from "../tools/index.js";
|
|
5
6
|
import { DirectusTransport } from "./transport.js";
|
|
6
7
|
import { useEnv } from "@directus/env";
|
|
7
8
|
import { ForbiddenError, InvalidPayloadError, isDirectusError } from "@directus/errors";
|
|
8
|
-
import { isObject,
|
|
9
|
+
import { isObject, toArray } from "@directus/utils";
|
|
9
10
|
import { fromZodError } from "zod-validation-error";
|
|
10
11
|
import { z } from "zod";
|
|
11
12
|
import { render, tokenize } from "micromustache";
|
|
@@ -166,19 +167,8 @@ var DirectusMCP = class {
|
|
|
166
167
|
if (tool.name === "system-prompt") {
|
|
167
168
|
request.params.arguments = { promptOverride: this.systemPrompt };
|
|
168
169
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
"data",
|
|
172
|
-
"keys",
|
|
173
|
-
"query"
|
|
174
|
-
]) {
|
|
175
|
-
const arg = request.params.arguments[field];
|
|
176
|
-
if (typeof arg === "string") {
|
|
177
|
-
request.params.arguments[field] = parseJSON(arg);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const { error, data: args } = tool.validateSchema?.safeParse(request.params.arguments) ?? { data: request.params.arguments };
|
|
170
|
+
const coercedArgs = request.params.arguments ? coerceJsonFields(request.params.arguments) : request.params.arguments;
|
|
171
|
+
const { error, data: args } = tool.validateSchema?.safeParse(coercedArgs) ?? { data: coercedArgs };
|
|
182
172
|
if (error) {
|
|
183
173
|
throw new InvalidPayloadError({ reason: fromZodError(error).message });
|
|
184
174
|
}
|
package/dist/ai/tools/utils.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { sanitizeQuery } from "../../utils/sanitize-query.js";
|
|
2
|
+
import { parseJSON } from "@directus/utils";
|
|
2
3
|
|
|
3
4
|
//#region src/ai/tools/utils.ts
|
|
5
|
+
const JSON_COERCE_FIELDS = [
|
|
6
|
+
"data",
|
|
7
|
+
"keys",
|
|
8
|
+
"query",
|
|
9
|
+
"headers"
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* LLMs sometimes return object/array arguments as stringified JSON.
|
|
13
|
+
* Coerce known fields back to native values before validation.
|
|
14
|
+
*/
|
|
15
|
+
function coerceJsonFields(args) {
|
|
16
|
+
const coerced = { ...args };
|
|
17
|
+
for (const field of JSON_COERCE_FIELDS) {
|
|
18
|
+
if (typeof coerced[field] === "string") {
|
|
19
|
+
try {
|
|
20
|
+
coerced[field] = parseJSON(coerced[field]);
|
|
21
|
+
} catch {}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return coerced;
|
|
25
|
+
}
|
|
4
26
|
/**
|
|
5
27
|
* Build a sanitized query object from a tool's args payload.
|
|
6
28
|
* - Ensures fields defaults to '*' when not provided
|
|
@@ -19,4 +41,4 @@ async function buildSanitizedQueryFromArgs(args, schema, accountability) {
|
|
|
19
41
|
}
|
|
20
42
|
|
|
21
43
|
//#endregion
|
|
22
|
-
export { buildSanitizedQueryFromArgs };
|
|
44
|
+
export { buildSanitizedQueryFromArgs, coerceJsonFields };
|
|
@@ -24,6 +24,7 @@ const router = Router();
|
|
|
24
24
|
const env = useEnv();
|
|
25
25
|
router.use(use_collection_default("directus_files"));
|
|
26
26
|
router.post("/folder/:pk", async_handler_default(async (req, res) => {
|
|
27
|
+
const logger = useLogger();
|
|
27
28
|
const service = new AssetsService({
|
|
28
29
|
accountability: req.accountability,
|
|
29
30
|
schema: req.schema
|
|
@@ -32,10 +33,33 @@ router.post("/folder/:pk", async_handler_default(async (req, res) => {
|
|
|
32
33
|
res.setHeader("Content-Type", "application/zip");
|
|
33
34
|
const folderName = `folder-${metadata["name"] ? metadata["name"] : "unknown"}-${getDateTimeFormatted()}.zip`;
|
|
34
35
|
res.setHeader("Content-Disposition", contentDisposition(folderName, { type: "attachment" }));
|
|
36
|
+
res.on("close", () => {
|
|
37
|
+
if (!res.writableEnded) {
|
|
38
|
+
archive.destroy();
|
|
39
|
+
archive.abort();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
35
42
|
archive.pipe(res);
|
|
36
|
-
|
|
43
|
+
try {
|
|
44
|
+
await complete();
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logger.error(error, `Couldn't archive folder ${req.params["pk"]} to the client`);
|
|
47
|
+
archive.destroy();
|
|
48
|
+
if (!res.headersSent) {
|
|
49
|
+
res.removeHeader("Content-Type");
|
|
50
|
+
res.removeHeader("Content-Disposition");
|
|
51
|
+
res.removeHeader("Cache-Control");
|
|
52
|
+
res.status(500).json({ errors: [{
|
|
53
|
+
message: "An unexpected error occurred.",
|
|
54
|
+
extensions: { code: "INTERNAL_SERVER_ERROR" }
|
|
55
|
+
}] });
|
|
56
|
+
} else {
|
|
57
|
+
res.end();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
37
60
|
}));
|
|
38
61
|
router.post("/files/", async_handler_default(async (req, res) => {
|
|
62
|
+
const logger = useLogger();
|
|
39
63
|
const service = new AssetsService({
|
|
40
64
|
accountability: req.accountability,
|
|
41
65
|
schema: req.schema
|
|
@@ -47,8 +71,30 @@ router.post("/files/", async_handler_default(async (req, res) => {
|
|
|
47
71
|
const { archive, complete } = await service.zipFiles(data.ids);
|
|
48
72
|
res.setHeader("Content-Type", "application/zip");
|
|
49
73
|
res.setHeader("Content-Disposition", `attachment; filename="files-${getDateTimeFormatted()}.zip"`);
|
|
74
|
+
res.on("close", () => {
|
|
75
|
+
if (!res.writableEnded) {
|
|
76
|
+
archive.destroy();
|
|
77
|
+
archive.abort();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
50
80
|
archive.pipe(res);
|
|
51
|
-
|
|
81
|
+
try {
|
|
82
|
+
await complete();
|
|
83
|
+
} catch (error$1) {
|
|
84
|
+
logger.error(error$1, `Couldn't archive files to the client`);
|
|
85
|
+
archive.destroy();
|
|
86
|
+
if (!res.headersSent) {
|
|
87
|
+
res.removeHeader("Content-Type");
|
|
88
|
+
res.removeHeader("Content-Disposition");
|
|
89
|
+
res.removeHeader("Cache-Control");
|
|
90
|
+
res.status(500).json({ errors: [{
|
|
91
|
+
message: "An unexpected error occurred.",
|
|
92
|
+
extensions: { code: "INTERNAL_SERVER_ERROR" }
|
|
93
|
+
}] });
|
|
94
|
+
} else {
|
|
95
|
+
res.end();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
52
98
|
}));
|
|
53
99
|
router.get("/:pk/:filename?", async_handler_default(async (req, res, next) => {
|
|
54
100
|
const payloadService = new PayloadService("directus_settings", { schema: req.schema });
|
|
@@ -183,8 +229,15 @@ router.get("/:pk/:filename?", async_handler_default(async (req, res, next) => {
|
|
|
183
229
|
res.setHeader("Content-Length", stat.size);
|
|
184
230
|
return res.end();
|
|
185
231
|
}
|
|
186
|
-
|
|
232
|
+
const sourceStream = await stream();
|
|
233
|
+
res.on("close", () => {
|
|
234
|
+
if (!res.writableEnded) {
|
|
235
|
+
sourceStream.destroy();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
sourceStream.on("error", (error) => {
|
|
187
239
|
logger.error(error, `Couldn't stream file ${file.id} to the client`);
|
|
240
|
+
sourceStream.destroy();
|
|
188
241
|
if (!res.headersSent) {
|
|
189
242
|
res.removeHeader("Content-Type");
|
|
190
243
|
res.removeHeader("Content-Disposition");
|
package/dist/services/assets.js
CHANGED
|
@@ -59,6 +59,7 @@ var AssetsService = class {
|
|
|
59
59
|
const deduper = new NameDeduper();
|
|
60
60
|
const storage = await getStorage();
|
|
61
61
|
for (const { id, folder, filename_download } of options.files) {
|
|
62
|
+
if (archive.destroyed) break;
|
|
62
63
|
const file = await this.sudoFilesService.readOne(id, { fields: [
|
|
63
64
|
"id",
|
|
64
65
|
"storage",
|
|
@@ -84,6 +85,7 @@ var AssetsService = class {
|
|
|
84
85
|
}
|
|
85
86
|
if (options.folders) {
|
|
86
87
|
for (const [, folder] of options.folders) {
|
|
88
|
+
if (archive.destroyed) break;
|
|
87
89
|
archive.append("", { name: folder + "/" });
|
|
88
90
|
}
|
|
89
91
|
}
|
package/dist/services/users.js
CHANGED
|
@@ -14,7 +14,7 @@ import { verifyJWT } from "../utils/jwt.js";
|
|
|
14
14
|
import { stall } from "../utils/stall.js";
|
|
15
15
|
import { SettingsService } from "./settings.js";
|
|
16
16
|
import { useEnv } from "@directus/env";
|
|
17
|
-
import { ForbiddenError, InvalidPayloadError, RecordNotUniqueError } from "@directus/errors";
|
|
17
|
+
import { ForbiddenError, InvalidInviteError, InvalidPayloadError, RecordNotUniqueError } from "@directus/errors";
|
|
18
18
|
import { getSimpleHash, toArray, validatePayload } from "@directus/utils";
|
|
19
19
|
import { isEmpty } from "lodash-es";
|
|
20
20
|
import { performance } from "perf_hooks";
|
|
@@ -314,7 +314,7 @@ var UsersService = class UsersService extends ItemsService {
|
|
|
314
314
|
if (scope !== "invite") throw new ForbiddenError();
|
|
315
315
|
const user = await this.getUserByEmail(email);
|
|
316
316
|
if (user?.status !== "invited") {
|
|
317
|
-
throw new
|
|
317
|
+
throw new InvalidInviteError();
|
|
318
318
|
}
|
|
319
319
|
const service = new UsersService({
|
|
320
320
|
knex: this.knex,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/api",
|
|
3
|
-
"version": "35.0.
|
|
3
|
+
"version": "35.0.2",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"directus",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"knex": "3.1.0",
|
|
123
123
|
"ldapts": "8.1.3",
|
|
124
124
|
"liquidjs": "10.25.0",
|
|
125
|
-
"lodash-es": "4.
|
|
125
|
+
"lodash-es": "4.18.1",
|
|
126
126
|
"marked": "16.4.1",
|
|
127
127
|
"micromustache": "8.0.3",
|
|
128
128
|
"mime-types": "3.0.1",
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
"rate-limiter-flexible": "7.2.0",
|
|
152
152
|
"rolldown": "1.0.0-beta.31",
|
|
153
153
|
"rollup": "4.59.0",
|
|
154
|
-
"samlify": "2.
|
|
154
|
+
"samlify": "2.12.0",
|
|
155
155
|
"sanitize-filename": "1.6.3",
|
|
156
156
|
"sanitize-html": "2.17.0",
|
|
157
157
|
"sharp": "0.34.5",
|
|
@@ -166,30 +166,30 @@
|
|
|
166
166
|
"zod": "4.1.12",
|
|
167
167
|
"zod-validation-error": "4.0.2",
|
|
168
168
|
"@directus/ai": "1.3.1",
|
|
169
|
-
"@directus/
|
|
170
|
-
"@directus/app": "15.7.0",
|
|
169
|
+
"@directus/app": "15.8.0",
|
|
171
170
|
"@directus/env": "5.7.1",
|
|
172
|
-
"@directus/
|
|
173
|
-
"@directus/errors": "2.3.
|
|
174
|
-
"@directus/extensions-registry": "3.0.
|
|
171
|
+
"@directus/constants": "14.3.0",
|
|
172
|
+
"@directus/errors": "2.3.1",
|
|
173
|
+
"@directus/extensions-registry": "3.0.24",
|
|
175
174
|
"@directus/format-title": "12.1.2",
|
|
176
|
-
"@directus/
|
|
177
|
-
"@directus/
|
|
175
|
+
"@directus/extensions": "3.0.23",
|
|
176
|
+
"@directus/memory": "3.1.7",
|
|
178
177
|
"@directus/pressure": "3.0.21",
|
|
178
|
+
"@directus/extensions-sdk": "17.1.2",
|
|
179
179
|
"@directus/schema": "13.0.7",
|
|
180
180
|
"@directus/schema-builder": "0.0.18",
|
|
181
181
|
"@directus/specs": "13.0.0",
|
|
182
182
|
"@directus/storage": "12.0.4",
|
|
183
|
-
"@directus/storage-driver-azure": "12.0.21",
|
|
184
|
-
"@directus/storage-driver-cloudinary": "12.0.21",
|
|
185
183
|
"@directus/storage-driver-gcs": "12.0.21",
|
|
184
|
+
"@directus/storage-driver-cloudinary": "12.0.21",
|
|
185
|
+
"@directus/storage-driver-azure": "12.0.21",
|
|
186
|
+
"@directus/storage-driver-local": "12.0.4",
|
|
186
187
|
"@directus/storage-driver-s3": "12.1.7",
|
|
187
188
|
"@directus/storage-driver-supabase": "3.0.21",
|
|
188
|
-
"@directus/utils": "13.4.0",
|
|
189
|
-
"@directus/storage-driver-local": "12.0.4",
|
|
190
189
|
"@directus/system-data": "4.4.0",
|
|
191
|
-
"directus": "
|
|
192
|
-
"
|
|
190
|
+
"@directus/validation": "2.0.22",
|
|
191
|
+
"directus": "11.17.2",
|
|
192
|
+
"@directus/utils": "13.4.0"
|
|
193
193
|
},
|
|
194
194
|
"devDependencies": {
|
|
195
195
|
"@directus/tsconfig": "4.0.0",
|