@directus/api 29.1.1 → 31.0.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.
Files changed (105) hide show
  1. package/dist/app.js +5 -0
  2. package/dist/auth/drivers/oauth2.js +17 -3
  3. package/dist/auth/drivers/openid.js +17 -3
  4. package/dist/constants.d.ts +1 -1
  5. package/dist/constants.js +9 -1
  6. package/dist/controllers/items.js +3 -4
  7. package/dist/controllers/mcp.d.ts +2 -0
  8. package/dist/controllers/mcp.js +33 -0
  9. package/dist/controllers/users.js +17 -7
  10. package/dist/controllers/versions.js +3 -2
  11. package/dist/database/errors/dialects/mssql.d.ts +1 -1
  12. package/dist/database/errors/dialects/mssql.js +18 -10
  13. package/dist/database/migrations/20250813A-add-mcp.d.ts +3 -0
  14. package/dist/database/migrations/20250813A-add-mcp.js +18 -0
  15. package/dist/database/run-ast/README.md +46 -0
  16. package/dist/mailer.js +3 -3
  17. package/dist/mcp/define.d.ts +2 -0
  18. package/dist/mcp/define.js +3 -0
  19. package/dist/mcp/index.d.ts +1 -0
  20. package/dist/mcp/index.js +1 -0
  21. package/dist/mcp/schema.d.ts +485 -0
  22. package/dist/mcp/schema.js +219 -0
  23. package/dist/mcp/server.d.ts +97 -0
  24. package/dist/mcp/server.js +310 -0
  25. package/dist/mcp/tools/assets.d.ts +3 -0
  26. package/dist/mcp/tools/assets.js +54 -0
  27. package/dist/mcp/tools/collections.d.ts +84 -0
  28. package/dist/mcp/tools/collections.js +90 -0
  29. package/dist/mcp/tools/fields.d.ts +101 -0
  30. package/dist/mcp/tools/fields.js +157 -0
  31. package/dist/mcp/tools/files.d.ts +235 -0
  32. package/dist/mcp/tools/files.js +103 -0
  33. package/dist/mcp/tools/flows.d.ts +323 -0
  34. package/dist/mcp/tools/flows.js +85 -0
  35. package/dist/mcp/tools/folders.d.ts +95 -0
  36. package/dist/mcp/tools/folders.js +96 -0
  37. package/dist/mcp/tools/index.d.ts +15 -0
  38. package/dist/mcp/tools/index.js +29 -0
  39. package/dist/mcp/tools/items.d.ts +87 -0
  40. package/dist/mcp/tools/items.js +141 -0
  41. package/dist/mcp/tools/operations.d.ts +171 -0
  42. package/dist/mcp/tools/operations.js +77 -0
  43. package/dist/mcp/tools/prompts/assets.md +8 -0
  44. package/dist/mcp/tools/prompts/collections.md +336 -0
  45. package/dist/mcp/tools/prompts/fields.md +521 -0
  46. package/dist/mcp/tools/prompts/files.md +180 -0
  47. package/dist/mcp/tools/prompts/flows.md +495 -0
  48. package/dist/mcp/tools/prompts/folders.md +34 -0
  49. package/dist/mcp/tools/prompts/index.d.ts +16 -0
  50. package/dist/mcp/tools/prompts/index.js +19 -0
  51. package/dist/mcp/tools/prompts/items.md +317 -0
  52. package/dist/mcp/tools/prompts/operations.md +721 -0
  53. package/dist/mcp/tools/prompts/relations.md +386 -0
  54. package/dist/mcp/tools/prompts/schema.md +130 -0
  55. package/dist/mcp/tools/prompts/system-prompt-description.md +1 -0
  56. package/dist/mcp/tools/prompts/system-prompt.md +44 -0
  57. package/dist/mcp/tools/prompts/trigger-flow.md +214 -0
  58. package/dist/mcp/tools/relations.d.ts +73 -0
  59. package/dist/mcp/tools/relations.js +93 -0
  60. package/dist/mcp/tools/schema.d.ts +54 -0
  61. package/dist/mcp/tools/schema.js +317 -0
  62. package/dist/mcp/tools/system.d.ts +3 -0
  63. package/dist/mcp/tools/system.js +22 -0
  64. package/dist/mcp/tools/trigger-flow.d.ts +8 -0
  65. package/dist/mcp/tools/trigger-flow.js +48 -0
  66. package/dist/mcp/transport.d.ts +13 -0
  67. package/dist/mcp/transport.js +18 -0
  68. package/dist/mcp/types.d.ts +56 -0
  69. package/dist/mcp/types.js +1 -0
  70. package/dist/middleware/respond.js +2 -2
  71. package/dist/services/authentication.js +36 -0
  72. package/dist/services/fields.js +4 -4
  73. package/dist/services/graphql/index.d.ts +2 -2
  74. package/dist/services/graphql/index.js +6 -5
  75. package/dist/services/graphql/resolvers/query.js +4 -39
  76. package/dist/services/items.js +38 -12
  77. package/dist/services/payload.d.ts +7 -3
  78. package/dist/services/payload.js +70 -12
  79. package/dist/services/server.js +1 -0
  80. package/dist/services/tfa.d.ts +1 -1
  81. package/dist/services/tfa.js +20 -5
  82. package/dist/services/versions.d.ts +6 -4
  83. package/dist/services/versions.js +84 -25
  84. package/dist/types/auth.d.ts +2 -1
  85. package/dist/utils/deep-map-response.d.ts +17 -0
  86. package/dist/utils/deep-map-response.js +61 -0
  87. package/dist/utils/get-relation-info.d.ts +1 -2
  88. package/dist/utils/permissions-cacheable.d.ts +8 -0
  89. package/dist/utils/{permissions-cachable.js → permissions-cacheable.js} +8 -6
  90. package/dist/utils/transaction.d.ts +1 -1
  91. package/dist/utils/transaction.js +18 -2
  92. package/dist/utils/versioning/deep-map-with-schema.d.ts +23 -0
  93. package/dist/utils/versioning/deep-map-with-schema.js +81 -0
  94. package/dist/utils/versioning/handle-version.d.ts +3 -0
  95. package/dist/utils/versioning/handle-version.js +96 -0
  96. package/dist/utils/versioning/merge-version-data.d.ts +2 -0
  97. package/dist/utils/versioning/merge-version-data.js +10 -0
  98. package/dist/utils/versioning/split-recursive.d.ts +4 -0
  99. package/dist/utils/versioning/split-recursive.js +27 -0
  100. package/package.json +31 -30
  101. package/dist/middleware/merge-content-versions.d.ts +0 -2
  102. package/dist/middleware/merge-content-versions.js +0 -26
  103. package/dist/utils/merge-version-data.d.ts +0 -3
  104. package/dist/utils/merge-version-data.js +0 -134
  105. package/dist/utils/permissions-cachable.d.ts +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/api",
3
- "version": "29.1.1",
3
+ "version": "31.0.0",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "keywords": [
6
6
  "directus",
@@ -59,8 +59,9 @@
59
59
  ],
60
60
  "dependencies": {
61
61
  "@authenio/samlify-node-xmllint": "2.0.0",
62
- "@aws-sdk/client-ses": "3.859.0",
62
+ "@aws-sdk/client-sesv2": "3.864.0",
63
63
  "@godaddy/terminus": "4.12.1",
64
+ "@modelcontextprotocol/sdk": "1.17.1",
64
65
  "@rollup/plugin-alias": "5.1.1",
65
66
  "@rollup/plugin-node-resolve": "16.0.1",
66
67
  "@rollup/plugin-virtual": "3.0.2",
@@ -102,7 +103,7 @@
102
103
  "ioredis": "5.7.0",
103
104
  "ip-matching": "2.1.2",
104
105
  "isolated-vm": "5.0.3",
105
- "joi": "17.13.3",
106
+ "joi": "18.0.1",
106
107
  "js-yaml": "4.1.0",
107
108
  "js2xmlparser": "5.0.0",
108
109
  "json2csv": "5.0.7",
@@ -139,8 +140,8 @@
139
140
  "proxy-addr": "2.0.7",
140
141
  "qs": "6.14.0",
141
142
  "rate-limiter-flexible": "7.2.0",
142
- "rollup": "4.46.2",
143
143
  "rolldown": "1.0.0-beta.31",
144
+ "rollup": "4.46.2",
144
145
  "samlify": "2.10.1",
145
146
  "sanitize-html": "2.17.0",
146
147
  "sharp": "0.34.3",
@@ -153,30 +154,30 @@
153
154
  "ws": "8.18.3",
154
155
  "zod": "4.0.14",
155
156
  "zod-validation-error": "4.0.1",
156
- "@directus/constants": "13.0.2",
157
- "@directus/env": "5.1.2",
158
- "@directus/app": "13.13.1",
159
- "@directus/extensions": "3.0.9",
160
- "@directus/errors": "2.0.3",
161
- "@directus/extensions-sdk": "16.0.0",
162
- "@directus/extensions-registry": "3.0.9",
163
- "@directus/pressure": "3.0.8",
164
- "@directus/memory": "3.0.8",
165
- "@directus/schema": "13.0.2",
166
- "@directus/schema-builder": "0.0.4",
167
- "@directus/storage": "12.0.1",
168
- "@directus/format-title": "12.0.1",
157
+ "@directus/env": "5.2.0",
158
+ "@directus/app": "14.0.0",
159
+ "@directus/errors": "2.0.4",
160
+ "@directus/extensions": "3.0.11",
161
+ "@directus/constants": "13.0.3",
162
+ "@directus/extensions-registry": "3.0.11",
163
+ "@directus/extensions-sdk": "16.0.2",
164
+ "@directus/format-title": "12.1.0",
165
+ "@directus/memory": "3.0.9",
166
+ "@directus/pressure": "3.0.9",
167
+ "@directus/schema": "13.0.3",
168
+ "@directus/schema-builder": "0.0.6",
169
169
  "@directus/specs": "11.1.1",
170
- "@directus/storage-driver-azure": "12.0.8",
171
- "@directus/storage-driver-cloudinary": "12.0.8",
172
- "@directus/storage-driver-local": "12.0.1",
173
- "@directus/storage-driver-s3": "12.0.8",
174
- "@directus/storage-driver-gcs": "12.0.8",
175
- "@directus/storage-driver-supabase": "3.0.8",
176
- "@directus/system-data": "3.2.1",
177
- "@directus/utils": "13.0.9",
178
- "@directus/validation": "2.0.8",
179
- "directus": "11.10.2"
170
+ "@directus/storage": "12.0.2",
171
+ "@directus/storage-driver-azure": "12.0.9",
172
+ "@directus/storage-driver-cloudinary": "12.0.9",
173
+ "@directus/storage-driver-gcs": "12.0.9",
174
+ "@directus/storage-driver-local": "12.0.2",
175
+ "@directus/storage-driver-s3": "12.0.9",
176
+ "@directus/storage-driver-supabase": "3.0.9",
177
+ "@directus/system-data": "3.3.0",
178
+ "@directus/utils": "13.0.10",
179
+ "directus": "11.12.0",
180
+ "@directus/validation": "2.0.9"
180
181
  },
181
182
  "devDependencies": {
182
183
  "@directus/tsconfig": "3.0.0",
@@ -220,8 +221,8 @@
220
221
  "knex-mock-client": "3.0.2",
221
222
  "typescript": "5.8.3",
222
223
  "vitest": "3.2.4",
223
- "@directus/schema-builder": "0.0.4",
224
- "@directus/types": "13.2.1"
224
+ "@directus/schema-builder": "0.0.6",
225
+ "@directus/types": "13.2.3"
225
226
  },
226
227
  "optionalDependencies": {
227
228
  "@keyv/redis": "3.0.1",
@@ -236,7 +237,7 @@
236
237
  "node": ">=22"
237
238
  },
238
239
  "scripts": {
239
- "build": "rimraf ./dist && tsc --project tsconfig.prod.json && copyfiles \"src/**/*.{yaml,liquid}\" -u 1 dist",
240
+ "build": "rimraf ./dist && tsc --project tsconfig.prod.json && copyfiles \"src/**/*.{yaml,liquid,md}\" -u 1 dist",
240
241
  "cli": "NODE_ENV=development SERVE_APP=false tsx src/cli/run.ts",
241
242
  "dev": "NODE_ENV=development SERVE_APP=true tsx watch --ignore extensions --clear-screen=false src/start.ts",
242
243
  "test": "vitest run",
@@ -1,2 +0,0 @@
1
- import type { RequestHandler } from 'express';
2
- export declare const mergeContentVersions: RequestHandler;
@@ -1,26 +0,0 @@
1
- import { isObject } from '@directus/utils';
2
- import { VersionsService } from '../services/versions.js';
3
- import asyncHandler from '../utils/async-handler.js';
4
- import { mergeVersionsRaw, mergeVersionsRecursive } from '../utils/merge-version-data.js';
5
- export const mergeContentVersions = asyncHandler(async (req, res, next) => {
6
- if (req.sanitizedQuery.version &&
7
- req.collection &&
8
- (req.singleton || req.params['pk']) &&
9
- 'data' in res.locals['payload']) {
10
- const originalData = res.locals['payload'].data;
11
- // only act on single item requests
12
- if (!isObject(originalData))
13
- return next();
14
- const versionsService = new VersionsService({ accountability: req.accountability ?? null, schema: req.schema });
15
- const versionData = await versionsService.getVersionSaves(req.sanitizedQuery.version, req.collection, req.params['pk']);
16
- if (!versionData || versionData.length === 0)
17
- return next();
18
- if (req.sanitizedQuery.versionRaw) {
19
- res.locals['payload'].data = mergeVersionsRaw(originalData, versionData);
20
- }
21
- else {
22
- res.locals['payload'].data = mergeVersionsRecursive(originalData, versionData, req.collection, req.schema);
23
- }
24
- }
25
- return next();
26
- });
@@ -1,3 +0,0 @@
1
- import type { Item, SchemaOverview } from '@directus/types';
2
- export declare function mergeVersionsRaw(item: Item, versionData: Partial<Item>[]): Item;
3
- export declare function mergeVersionsRecursive(item: Item, versionData: Item[], collection: string, schema: SchemaOverview): Item;
@@ -1,134 +0,0 @@
1
- import { isObject } from '@directus/utils';
2
- import Joi from 'joi';
3
- import { cloneDeep } from 'lodash-es';
4
- const alterationSchema = Joi.object({
5
- create: Joi.array().items(Joi.object().unknown()),
6
- update: Joi.array().items(Joi.object().unknown()),
7
- delete: Joi.array().items(Joi.string(), Joi.number()),
8
- });
9
- export function mergeVersionsRaw(item, versionData) {
10
- const result = cloneDeep(item);
11
- for (const versionRecord of versionData) {
12
- for (const key of Object.keys(versionRecord)) {
13
- result[key] = versionRecord[key];
14
- }
15
- }
16
- return result;
17
- }
18
- export function mergeVersionsRecursive(item, versionData, collection, schema) {
19
- if (versionData.length === 0)
20
- return item;
21
- return recursiveMerging(item, versionData, collection, schema);
22
- }
23
- function recursiveMerging(data, versionData, collection, schema) {
24
- const result = cloneDeep(data);
25
- const relations = getRelations(collection, schema);
26
- for (const versionRecord of versionData) {
27
- if (!isObject(versionRecord)) {
28
- continue;
29
- }
30
- for (const key of Object.keys(data)) {
31
- if (key in versionRecord === false) {
32
- continue;
33
- }
34
- const currentValue = data[key];
35
- const newValue = versionRecord[key];
36
- if (typeof newValue !== 'object' || newValue === null) {
37
- // primitive type substitution, json and non relational array values are handled in the next check
38
- result[key] = newValue;
39
- continue;
40
- }
41
- if (key in relations === false) {
42
- // check for m2a exception
43
- if (isManyToAnyCollection(collection, schema) && key === 'item') {
44
- const item = addMissingKeys(isObject(currentValue) ? currentValue : {}, newValue);
45
- result[key] = recursiveMerging(item, [newValue], data['collection'], schema);
46
- }
47
- else {
48
- // item is not a relation
49
- result[key] = newValue;
50
- }
51
- continue;
52
- }
53
- const { error } = alterationSchema.validate(newValue);
54
- if (error) {
55
- if (typeof newValue === 'object' && key in relations) {
56
- const newItem = !currentValue || typeof currentValue !== 'object' ? newValue : currentValue;
57
- result[key] = recursiveMerging(newItem, [newValue], relations[key], schema);
58
- }
59
- continue;
60
- }
61
- const alterations = newValue;
62
- const currentPrimaryKeyField = schema.collections[collection].primary;
63
- const relatedPrimaryKeyField = schema.collections[relations[key]].primary;
64
- const mergedRelation = [];
65
- if (Array.isArray(currentValue)) {
66
- if (alterations.delete.length > 0) {
67
- for (const currentItem of currentValue) {
68
- const currentId = typeof currentItem === 'object' ? currentItem[currentPrimaryKeyField] : currentItem;
69
- if (alterations.delete.includes(currentId) === false) {
70
- mergedRelation.push(currentItem);
71
- }
72
- }
73
- }
74
- else {
75
- mergedRelation.push(...currentValue);
76
- }
77
- if (alterations.update.length > 0) {
78
- for (const updatedItem of alterations.update) {
79
- // find existing item to update
80
- const itemIndex = mergedRelation.findIndex((currentItem) => currentItem[relatedPrimaryKeyField] === updatedItem[currentPrimaryKeyField]);
81
- if (itemIndex === -1) {
82
- // check for raw primary keys
83
- const pkIndex = mergedRelation.findIndex((currentItem) => currentItem === updatedItem[currentPrimaryKeyField]);
84
- if (pkIndex === -1) {
85
- // nothing to update so add the item as is
86
- mergedRelation.push(updatedItem);
87
- }
88
- else {
89
- mergedRelation[pkIndex] = updatedItem;
90
- }
91
- continue;
92
- }
93
- const item = addMissingKeys(mergedRelation[itemIndex], updatedItem);
94
- mergedRelation[itemIndex] = recursiveMerging(item, [updatedItem], relations[key], schema);
95
- }
96
- }
97
- }
98
- if (alterations.create.length > 0) {
99
- for (const createdItem of alterations.create) {
100
- const item = addMissingKeys({}, createdItem);
101
- mergedRelation.push(recursiveMerging(item, [createdItem], relations[key], schema));
102
- }
103
- }
104
- result[key] = mergedRelation;
105
- }
106
- }
107
- return result;
108
- }
109
- function addMissingKeys(item, edits) {
110
- const result = { ...item };
111
- for (const key of Object.keys(edits)) {
112
- if (key in item === false) {
113
- result[key] = null;
114
- }
115
- }
116
- return result;
117
- }
118
- function isManyToAnyCollection(collection, schema) {
119
- const relation = schema.relations.find((relation) => relation.collection === collection && relation.meta?.many_collection === collection);
120
- if (!relation || !relation.meta?.one_field || !relation.related_collection)
121
- return false;
122
- return Boolean(schema.collections[relation.related_collection]?.fields[relation.meta.one_field]?.special.includes('m2a'));
123
- }
124
- function getRelations(collection, schema) {
125
- return schema.relations.reduce((result, relation) => {
126
- if (relation.related_collection === collection && relation.meta?.one_field) {
127
- result[relation.meta.one_field] = relation.collection;
128
- }
129
- if (relation.collection === collection && relation.related_collection) {
130
- result[relation.field] = relation.related_collection;
131
- }
132
- return result;
133
- }, {});
134
- }
@@ -1,8 +0,0 @@
1
- import type { Accountability, Filter } from '@directus/types';
2
- import type { Context } from '../permissions/types.js';
3
- /**
4
- * Check if the read permissions for a collection contain the dynamic variable $NOW.
5
- * If they do, the permissions are not cachable.
6
- */
7
- export declare function permissionsCachable(collection: string | undefined, context: Context, accountability?: Accountability): Promise<boolean>;
8
- export declare function filter_has_now(filter: Filter): boolean;