@directus/api 32.1.0 → 32.2.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 (175) hide show
  1. package/dist/ai/chat/constants/system-prompt.d.ts +1 -0
  2. package/dist/ai/chat/constants/system-prompt.js +51 -0
  3. package/dist/ai/chat/controllers/chat.post.d.ts +2 -0
  4. package/dist/ai/chat/controllers/chat.post.js +47 -0
  5. package/dist/ai/chat/lib/create-ui-stream.d.ts +15 -0
  6. package/dist/ai/chat/lib/create-ui-stream.js +42 -0
  7. package/dist/ai/chat/middleware/load-settings.d.ts +2 -0
  8. package/dist/ai/chat/middleware/load-settings.js +18 -0
  9. package/dist/ai/chat/models/chat-request.d.ts +34 -0
  10. package/dist/ai/chat/models/chat-request.js +26 -0
  11. package/dist/ai/chat/models/providers.d.ts +9 -0
  12. package/dist/ai/chat/models/providers.js +9 -0
  13. package/dist/ai/chat/router.d.ts +1 -0
  14. package/dist/ai/chat/router.js +5 -0
  15. package/dist/ai/chat/utils/chat-request-tool-to-ai-sdk-tool.d.ts +9 -0
  16. package/dist/ai/chat/utils/chat-request-tool-to-ai-sdk-tool.js +38 -0
  17. package/dist/ai/chat/utils/fix-error-tool-calls.d.ts +12 -0
  18. package/dist/ai/chat/utils/fix-error-tool-calls.js +30 -0
  19. package/dist/ai/chat/utils/parse-json-schema-7.d.ts +13 -0
  20. package/dist/ai/chat/utils/parse-json-schema-7.js +75 -0
  21. package/dist/{mcp → ai/mcp}/server.d.ts +13 -16
  22. package/dist/{mcp → ai/mcp}/server.js +4 -13
  23. package/dist/ai/mcp/types.d.ts +15 -0
  24. package/dist/{mcp/tools/assets.js → ai/tools/assets/index.js} +8 -5
  25. package/dist/{mcp/tools/collections.js → ai/tools/collections/index.js} +7 -4
  26. package/dist/{mcp/tools/fields.js → ai/tools/fields/index.js} +12 -9
  27. package/dist/{mcp/tools/files.js → ai/tools/files/index.js} +11 -5
  28. package/dist/{mcp/tools/flows.js → ai/tools/flows/index.js} +11 -5
  29. package/dist/{mcp/tools/folders.js → ai/tools/folders/index.js} +12 -5
  30. package/dist/ai/tools/index.d.ts +15 -0
  31. package/dist/ai/tools/index.js +29 -0
  32. package/dist/{mcp/tools/items.js → ai/tools/items/index.js} +13 -6
  33. package/dist/{mcp/tools/prompts/items.md → ai/tools/items/prompt.md} +19 -15
  34. package/dist/{mcp/tools/operations.d.ts → ai/tools/operations/index.d.ts} +46 -0
  35. package/dist/{mcp/tools/operations.js → ai/tools/operations/index.js} +12 -5
  36. package/dist/{mcp/tools/relations.js → ai/tools/relations/index.js} +7 -4
  37. package/dist/{mcp/tools/schema.d.ts → ai/tools/schema/index.d.ts} +1 -1
  38. package/dist/{mcp/tools/schema.js → ai/tools/schema/index.js} +9 -6
  39. package/dist/{mcp/tools/system.js → ai/tools/system/index.js} +7 -4
  40. package/dist/{mcp/tools/trigger-flow.js → ai/tools/trigger-flow/index.js} +8 -5
  41. package/dist/{mcp → ai/tools}/types.d.ts +1 -17
  42. package/dist/ai/tools/utils.d.ts +9 -0
  43. package/dist/ai/tools/utils.js +17 -0
  44. package/dist/app.js +5 -0
  45. package/dist/auth/drivers/oauth2.d.ts +2 -1
  46. package/dist/auth/drivers/oauth2.js +17 -22
  47. package/dist/auth/drivers/openid.d.ts +2 -1
  48. package/dist/auth/drivers/openid.js +13 -18
  49. package/dist/auth/drivers/saml.js +6 -3
  50. package/dist/controllers/assets.js +39 -2
  51. package/dist/controllers/mcp.js +1 -1
  52. package/dist/database/migrations/20240806A-permissions-policies.js +2 -2
  53. package/dist/database/migrations/20251103A-add-ai-settings.d.ts +3 -0
  54. package/dist/database/migrations/20251103A-add-ai-settings.js +14 -0
  55. package/dist/database/run-ast/run-ast.js +1 -1
  56. package/dist/extensions/lib/installation/manager.js +5 -9
  57. package/dist/extensions/lib/sync/status.d.ts +11 -0
  58. package/dist/extensions/lib/sync/status.js +34 -0
  59. package/dist/extensions/lib/sync/sync.d.ts +6 -0
  60. package/dist/extensions/lib/sync/sync.js +90 -0
  61. package/dist/extensions/lib/sync/tracker.d.ts +18 -0
  62. package/dist/extensions/lib/sync/tracker.js +71 -0
  63. package/dist/extensions/lib/sync/utils.d.ts +24 -0
  64. package/dist/extensions/lib/sync/utils.js +62 -0
  65. package/dist/extensions/manager.d.ts +8 -4
  66. package/dist/extensions/manager.js +30 -13
  67. package/dist/middleware/respond.js +2 -2
  68. package/dist/permissions/lib/fetch-policies.d.ts +1 -1
  69. package/dist/permissions/lib/fetch-roles-tree.d.ts +6 -3
  70. package/dist/permissions/lib/fetch-roles-tree.js +5 -27
  71. package/dist/permissions/modules/fetch-global-access/fetch-global-access.d.ts +9 -7
  72. package/dist/permissions/modules/fetch-global-access/fetch-global-access.js +17 -9
  73. package/dist/permissions/modules/fetch-policies-ip-access/fetch-policies-ip-access.d.ts +1 -1
  74. package/dist/permissions/utils/fetch-raw-permissions.d.ts +1 -1
  75. package/dist/permissions/utils/fetch-share-info.d.ts +1 -1
  76. package/dist/permissions/utils/fetch-share-info.js +1 -1
  77. package/dist/permissions/utils/filter-policies-by-ip.js +1 -1
  78. package/dist/permissions/utils/get-permissions-for-share.js +8 -8
  79. package/dist/permissions/utils/with-cache.d.ts +8 -6
  80. package/dist/permissions/utils/with-cache.js +12 -10
  81. package/dist/request/is-denied-ip.js +2 -2
  82. package/dist/services/assets/name-deduper.d.ts +7 -0
  83. package/dist/services/assets/name-deduper.js +23 -0
  84. package/dist/services/assets.d.ts +15 -2
  85. package/dist/services/assets.js +98 -5
  86. package/dist/services/authentication.js +4 -4
  87. package/dist/services/comments.js +2 -2
  88. package/dist/services/extensions.js +4 -0
  89. package/dist/services/folders.d.ts +27 -2
  90. package/dist/services/folders.js +75 -0
  91. package/dist/services/graphql/resolvers/query.js +1 -1
  92. package/dist/services/import-export.d.ts +1 -1
  93. package/dist/services/import-export.js +4 -5
  94. package/dist/services/notifications.js +2 -2
  95. package/dist/services/payload.js +20 -0
  96. package/dist/services/roles.js +2 -2
  97. package/dist/services/tus/server.js +3 -3
  98. package/dist/telemetry/utils/get-settings.d.ts +15 -0
  99. package/dist/telemetry/utils/get-settings.js +25 -9
  100. package/dist/test-utils/README.md +95 -24
  101. package/dist/test-utils/cache.d.ts +2 -2
  102. package/dist/test-utils/cache.js +2 -2
  103. package/dist/test-utils/{fields-service.d.ts → services/fields-service.d.ts} +1 -1
  104. package/dist/test-utils/{fields-service.js → services/fields-service.js} +3 -2
  105. package/dist/test-utils/services/files-service.d.ts +28 -0
  106. package/dist/test-utils/services/files-service.js +34 -0
  107. package/dist/test-utils/services/folders-service.d.ts +28 -0
  108. package/dist/test-utils/services/folders-service.js +33 -0
  109. package/dist/utils/encrypt.d.ts +2 -0
  110. package/dist/utils/encrypt.js +64 -0
  111. package/dist/utils/get-accountability-for-role.js +2 -2
  112. package/dist/utils/get-accountability-for-token.js +4 -4
  113. package/dist/utils/get-cache-key.js +2 -2
  114. package/dist/utils/is-login-redirect-allowed.d.ts +4 -0
  115. package/dist/{auth/utils → utils}/is-login-redirect-allowed.js +8 -16
  116. package/dist/utils/require-text.d.ts +1 -0
  117. package/dist/utils/require-text.js +4 -0
  118. package/dist/utils/require-yaml.js +2 -2
  119. package/package.json +31 -25
  120. package/dist/auth/utils/generate-callback-url.d.ts +0 -8
  121. package/dist/auth/utils/generate-callback-url.js +0 -11
  122. package/dist/auth/utils/is-login-redirect-allowed.d.ts +0 -8
  123. package/dist/extensions/lib/sync-extensions.d.ts +0 -3
  124. package/dist/extensions/lib/sync-extensions.js +0 -70
  125. package/dist/extensions/lib/sync-status.d.ts +0 -10
  126. package/dist/extensions/lib/sync-status.js +0 -27
  127. package/dist/mcp/tools/index.d.ts +0 -15
  128. package/dist/mcp/tools/index.js +0 -29
  129. package/dist/mcp/tools/prompts/index.d.ts +0 -16
  130. package/dist/mcp/tools/prompts/index.js +0 -19
  131. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.d.ts +0 -5
  132. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-roles.js +0 -7
  133. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.d.ts +0 -5
  134. package/dist/permissions/modules/fetch-global-access/lib/fetch-global-access-for-user.js +0 -10
  135. package/dist/permissions/modules/fetch-global-access/types.d.ts +0 -4
  136. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.d.ts +0 -4
  137. package/dist/permissions/modules/fetch-global-access/utils/fetch-global-access-for-query.js +0 -27
  138. package/dist/utils/get-date-formatted.d.ts +0 -1
  139. package/dist/utils/get-date-formatted.js +0 -10
  140. package/dist/utils/ip-in-networks.d.ts +0 -6
  141. package/dist/utils/ip-in-networks.js +0 -13
  142. /package/dist/{mcp → ai/mcp}/index.d.ts +0 -0
  143. /package/dist/{mcp → ai/mcp}/index.js +0 -0
  144. /package/dist/{mcp → ai/mcp}/transport.d.ts +0 -0
  145. /package/dist/{mcp → ai/mcp}/transport.js +0 -0
  146. /package/dist/{mcp → ai/mcp}/types.js +0 -0
  147. /package/dist/{mcp/tools/assets.d.ts → ai/tools/assets/index.d.ts} +0 -0
  148. /package/dist/{mcp/tools/prompts/assets.md → ai/tools/assets/prompt.md} +0 -0
  149. /package/dist/{mcp/tools/collections.d.ts → ai/tools/collections/index.d.ts} +0 -0
  150. /package/dist/{mcp/tools/prompts/collections.md → ai/tools/collections/prompt.md} +0 -0
  151. /package/dist/{mcp/define.d.ts → ai/tools/define-tool.d.ts} +0 -0
  152. /package/dist/{mcp/define.js → ai/tools/define-tool.js} +0 -0
  153. /package/dist/{mcp/tools/fields.d.ts → ai/tools/fields/index.d.ts} +0 -0
  154. /package/dist/{mcp/tools/prompts/fields.md → ai/tools/fields/prompt.md} +0 -0
  155. /package/dist/{mcp/tools/files.d.ts → ai/tools/files/index.d.ts} +0 -0
  156. /package/dist/{mcp/tools/prompts/files.md → ai/tools/files/prompt.md} +0 -0
  157. /package/dist/{mcp/tools/flows.d.ts → ai/tools/flows/index.d.ts} +0 -0
  158. /package/dist/{mcp/tools/prompts/flows.md → ai/tools/flows/prompt.md} +0 -0
  159. /package/dist/{mcp/tools/folders.d.ts → ai/tools/folders/index.d.ts} +0 -0
  160. /package/dist/{mcp/tools/prompts/folders.md → ai/tools/folders/prompt.md} +0 -0
  161. /package/dist/{mcp/tools/items.d.ts → ai/tools/items/index.d.ts} +0 -0
  162. /package/dist/{mcp/tools/prompts/operations.md → ai/tools/operations/prompt.md} +0 -0
  163. /package/dist/{mcp/tools/relations.d.ts → ai/tools/relations/index.d.ts} +0 -0
  164. /package/dist/{mcp/tools/prompts/relations.md → ai/tools/relations/prompt.md} +0 -0
  165. /package/dist/{mcp/tools/prompts/schema.md → ai/tools/schema/prompt.md} +0 -0
  166. /package/dist/{mcp → ai/tools}/schema.d.ts +0 -0
  167. /package/dist/{mcp → ai/tools}/schema.js +0 -0
  168. /package/dist/{mcp/tools/system.d.ts → ai/tools/system/index.d.ts} +0 -0
  169. /package/dist/{mcp/tools/prompts/system-prompt-description.md → ai/tools/system/prompt-description.md} +0 -0
  170. /package/dist/{mcp/tools/prompts/system-prompt.md → ai/tools/system/prompt.md} +0 -0
  171. /package/dist/{mcp/tools/trigger-flow.d.ts → ai/tools/trigger-flow/index.d.ts} +0 -0
  172. /package/dist/{mcp/tools/prompts/trigger-flow.md → ai/tools/trigger-flow/prompt.md} +0 -0
  173. /package/dist/{permissions/modules/fetch-global-access → ai/tools}/types.js +0 -0
  174. /package/dist/test-utils/{items-service.d.ts → services/items-service.d.ts} +0 -0
  175. /package/dist/test-utils/{items-service.js → services/items-service.js} +0 -0
@@ -1,23 +1,19 @@
1
1
  import { useEnv } from '@directus/env';
2
2
  import { toArray } from '@directus/utils';
3
- import { useLogger } from '../../logger/index.js';
4
- import isUrlAllowed from '../../utils/is-url-allowed.js';
3
+ import { useLogger } from '../logger/index.js';
4
+ import isUrlAllowed from './is-url-allowed.js';
5
5
  /**
6
- * Check if the redirect URL is allowed
7
- * @param originUrl Origin URL
8
- * @param provider OAuth provider name
9
- * @param redirect URL to redirect to
10
- * @returns True if the redirect is allowed, false otherwise
6
+ * Checks if the defined redirect after successful SSO login is in the allow list
11
7
  */
12
- export function isLoginRedirectAllowed(provider, originUrl, redirect) {
8
+ export function isLoginRedirectAllowed(redirect, provider) {
13
9
  if (!redirect)
14
10
  return true; // empty redirect
15
11
  if (typeof redirect !== 'string')
16
12
  return false; // invalid type
17
13
  const env = useEnv();
18
14
  const publicUrl = env['PUBLIC_URL'];
19
- if (!URL.canParse(redirect)) {
20
- if (!redirect.startsWith('//')) {
15
+ if (URL.canParse(redirect) === false) {
16
+ if (redirect.startsWith('//') === false) {
21
17
  // should be a relative path like `/admin/test`
22
18
  return true;
23
19
  }
@@ -25,10 +21,6 @@ export function isLoginRedirectAllowed(provider, originUrl, redirect) {
25
21
  return false;
26
22
  }
27
23
  const { protocol: redirectProtocol, hostname: redirectDomain } = new URL(redirect);
28
- const redirectUrl = `${redirectProtocol}//${redirectDomain}`;
29
- // Security check: redirect URL must match the request origin
30
- if (redirectUrl !== originUrl)
31
- return false;
32
24
  const envKey = `AUTH_${provider.toUpperCase()}_REDIRECT_ALLOW_LIST`;
33
25
  if (envKey in env) {
34
26
  if (isUrlAllowed(redirect, [...toArray(env[envKey]), publicUrl]))
@@ -38,7 +30,7 @@ export function isLoginRedirectAllowed(provider, originUrl, redirect) {
38
30
  useLogger().error('Invalid PUBLIC_URL for login redirect');
39
31
  return false;
40
32
  }
41
- const { protocol: publicProtocol, hostname: publicDomain } = new URL(publicUrl);
42
33
  // allow redirects to the defined PUBLIC_URL
43
- return redirectUrl === `${publicProtocol}//${publicDomain}`;
34
+ const { protocol: publicProtocol, hostname: publicDomain } = new URL(publicUrl);
35
+ return `${redirectProtocol}//${redirectDomain}` === `${publicProtocol}//${publicDomain}`;
44
36
  }
@@ -0,0 +1 @@
1
+ export declare function requireText(filepath: string): string;
@@ -0,0 +1,4 @@
1
+ import fse from 'fs-extra';
2
+ export function requireText(filepath) {
3
+ return fse.readFileSync(filepath, 'utf8');
4
+ }
@@ -1,6 +1,6 @@
1
- import fse from 'fs-extra';
2
1
  import yaml from 'js-yaml';
2
+ import { requireText } from './require-text.js';
3
3
  export function requireYAML(filepath) {
4
- const yamlRaw = fse.readFileSync(filepath, 'utf8');
4
+ const yamlRaw = requireText(filepath);
5
5
  return yaml.load(yamlRaw);
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/api",
3
- "version": "32.1.0",
3
+ "version": "32.2.0",
4
4
  "description": "Directus is a real-time API and App dashboard for managing SQL database content",
5
5
  "keywords": [
6
6
  "directus",
@@ -58,15 +58,19 @@
58
58
  "dist"
59
59
  ],
60
60
  "dependencies": {
61
+ "@ai-sdk/anthropic": "3.0.0-beta.53",
62
+ "@ai-sdk/openai": "3.0.0-beta.57",
61
63
  "@authenio/samlify-node-xmllint": "2.0.0",
62
64
  "@aws-sdk/client-sesv2": "3.928.0",
63
65
  "@godaddy/terminus": "4.12.1",
64
- "@modelcontextprotocol/sdk": "1.21.1",
66
+ "@modelcontextprotocol/sdk": "1.24.0",
65
67
  "@rollup/plugin-alias": "5.1.1",
66
68
  "@rollup/plugin-node-resolve": "16.0.3",
67
69
  "@rollup/plugin-virtual": "3.0.2",
68
70
  "@tus/server": "2.3.0",
69
71
  "@tus/utils": "0.6.0",
72
+ "archiver": "7.0.1",
73
+ "ai": "6.0.0-beta.98",
70
74
  "argon2": "0.44.0",
71
75
  "async": "3.2.6",
72
76
  "async-mutex": "0.5.0",
@@ -81,6 +85,7 @@
81
85
  "cookie": "1.0.2",
82
86
  "cookie-parser": "1.4.7",
83
87
  "cors": "2.8.5",
88
+ "cron": "4.3.4",
84
89
  "date-fns": "4.1.0",
85
90
  "deep-diff": "1.0.2",
86
91
  "destroy": "1.2.0",
@@ -106,7 +111,7 @@
106
111
  "js-yaml": "4.1.1",
107
112
  "js2xmlparser": "5.0.0",
108
113
  "json2csv": "5.0.7",
109
- "jsonwebtoken": "9.0.2",
114
+ "jsonwebtoken": "9.0.3",
110
115
  "keyv": "5.5.3",
111
116
  "knex": "3.1.0",
112
117
  "ldapjs": "2.3.3",
@@ -120,7 +125,6 @@
120
125
  "ms": "2.1.3",
121
126
  "nanoid": "5.1.6",
122
127
  "node-machine-id": "1.1.12",
123
- "cron": "4.3.4",
124
128
  "nodemailer": "7.0.10",
125
129
  "object-hash": "3.0.0",
126
130
  "openapi3-ts": "4.5.0",
@@ -141,7 +145,8 @@
141
145
  "rate-limiter-flexible": "7.2.0",
142
146
  "rolldown": "1.0.0-beta.31",
143
147
  "rollup": "4.52.5",
144
- "samlify": "2.10.1",
148
+ "samlify": "2.10.2",
149
+ "sanitize-filename": "1.6.3",
145
150
  "sanitize-html": "2.17.0",
146
151
  "sharp": "0.34.5",
147
152
  "snappy": "7.3.3",
@@ -153,34 +158,35 @@
153
158
  "ws": "8.18.3",
154
159
  "zod": "4.1.12",
155
160
  "zod-validation-error": "4.0.2",
156
- "@directus/app": "14.2.0",
157
- "@directus/env": "5.3.2",
161
+ "@directus/app": "14.4.0",
162
+ "@directus/extensions": "3.0.15",
163
+ "@directus/errors": "2.1.0",
164
+ "@directus/extensions-sdk": "17.0.4",
158
165
  "@directus/constants": "14.0.0",
159
- "@directus/errors": "2.0.5",
160
- "@directus/extensions-registry": "3.0.14",
161
- "@directus/extensions-sdk": "17.0.3",
166
+ "@directus/extensions-registry": "3.0.15",
167
+ "@directus/env": "5.3.3",
162
168
  "@directus/format-title": "12.1.1",
163
- "@directus/extensions": "3.0.14",
164
- "@directus/pressure": "3.0.12",
169
+ "@directus/memory": "3.0.13",
170
+ "@directus/pressure": "3.0.13",
165
171
  "@directus/schema": "13.0.4",
166
- "@directus/memory": "3.0.12",
167
- "@directus/schema-builder": "0.0.9",
168
172
  "@directus/storage": "12.0.3",
169
173
  "@directus/specs": "11.2.0",
170
- "@directus/storage-driver-azure": "12.0.12",
171
- "@directus/storage-driver-cloudinary": "12.0.12",
172
- "@directus/storage-driver-gcs": "12.0.12",
173
- "@directus/storage-driver-s3": "12.0.12",
174
+ "@directus/schema-builder": "0.0.10",
175
+ "@directus/storage-driver-azure": "12.0.13",
176
+ "@directus/storage-driver-cloudinary": "12.0.13",
177
+ "@directus/storage-driver-gcs": "12.0.13",
174
178
  "@directus/storage-driver-local": "12.0.3",
175
- "@directus/storage-driver-supabase": "3.0.12",
176
- "@directus/system-data": "3.4.2",
177
- "@directus/validation": "2.0.12",
178
- "@directus/utils": "13.0.13",
179
- "directus": "11.13.3"
179
+ "@directus/system-data": "3.5.0",
180
+ "@directus/storage-driver-supabase": "3.0.13",
181
+ "@directus/utils": "13.1.0",
182
+ "@directus/validation": "2.0.13",
183
+ "@directus/storage-driver-s3": "12.0.13",
184
+ "directus": "11.14.0"
180
185
  },
181
186
  "devDependencies": {
182
187
  "@directus/tsconfig": "3.0.0",
183
188
  "@ngneat/falso": "8.0.2",
189
+ "@types/archiver": "7.0.0",
184
190
  "@types/async": "3.2.25",
185
191
  "@types/busboy": "1.5.4",
186
192
  "@types/bytes": "3.1.5",
@@ -219,8 +225,8 @@
219
225
  "knex-mock-client": "3.0.2",
220
226
  "typescript": "5.9.3",
221
227
  "vitest": "3.2.4",
222
- "@directus/types": "13.4.0",
223
- "@directus/schema-builder": "0.0.9"
228
+ "@directus/schema-builder": "0.0.10",
229
+ "@directus/types": "13.5.0"
224
230
  },
225
231
  "optionalDependencies": {
226
232
  "@keyv/redis": "3.0.1",
@@ -1,8 +0,0 @@
1
- /**
2
- * Generate callback URL from origin
3
- *
4
- * @param string Origin URL
5
- * @param providerName OAuth provider name
6
- * @returns url
7
- */
8
- export declare function generateCallbackUrl(providerName: string, originUrl: string): string;
@@ -1,11 +0,0 @@
1
- import { Url } from '../../utils/url.js';
2
- /**
3
- * Generate callback URL from origin
4
- *
5
- * @param string Origin URL
6
- * @param providerName OAuth provider name
7
- * @returns url
8
- */
9
- export function generateCallbackUrl(providerName, originUrl) {
10
- return new Url(originUrl).addPath('auth', 'login', providerName, 'callback').toString();
11
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * Check if the redirect URL is allowed
3
- * @param originUrl Origin URL
4
- * @param provider OAuth provider name
5
- * @param redirect URL to redirect to
6
- * @returns True if the redirect is allowed, false otherwise
7
- */
8
- export declare function isLoginRedirectAllowed(provider: string, originUrl: string, redirect: unknown): boolean;
@@ -1,3 +0,0 @@
1
- export declare const syncExtensions: (options?: {
2
- force: boolean;
3
- }) => Promise<void>;
@@ -1,70 +0,0 @@
1
- import { useEnv } from '@directus/env';
2
- import { exists } from 'fs-extra';
3
- import mid from 'node-machine-id';
4
- import { createWriteStream } from 'node:fs';
5
- import { mkdir, rm } from 'node:fs/promises';
6
- import { dirname, join, relative, resolve, sep } from 'node:path';
7
- import { pipeline } from 'node:stream/promises';
8
- import Queue from 'p-queue';
9
- import { useBus } from '../../bus/index.js';
10
- import { useLock } from '../../lock/index.js';
11
- import { useLogger } from '../../logger/index.js';
12
- import { getStorage } from '../../storage/index.js';
13
- import { getExtensionsPath } from './get-extensions-path.js';
14
- import { SyncStatus, getSyncStatus, setSyncStatus } from './sync-status.js';
15
- export const syncExtensions = async (options) => {
16
- const lock = useLock();
17
- const messenger = useBus();
18
- const env = useEnv();
19
- const logger = useLogger();
20
- if (!options?.force) {
21
- const isDone = (await getSyncStatus()) === SyncStatus.DONE;
22
- if (isDone)
23
- return;
24
- }
25
- const machineId = await mid.machineId();
26
- const machineKey = `extensions-sync/${machineId}`;
27
- const processId = await lock.increment(machineKey);
28
- const currentProcessShouldHandleSync = processId === 1;
29
- if (currentProcessShouldHandleSync === false) {
30
- logger.trace('Extensions already being synced to this machine from another process.');
31
- // Wait until the process that called the lock publishes a message that the syncing is complete
32
- return new Promise((resolve) => {
33
- messenger.subscribe(machineKey, () => resolve());
34
- });
35
- }
36
- try {
37
- const extensionsPath = getExtensionsPath();
38
- const storageExtensionsPath = env['EXTENSIONS_PATH'];
39
- if (await exists(extensionsPath)) {
40
- // In case the FS still contains the cached extensions from a previous invocation. We have to
41
- // clear them out to ensure the remote extensions folder remains the source of truth for all
42
- // extensions that are loaded.
43
- await rm(extensionsPath, { recursive: true, force: true });
44
- }
45
- // Ensure that the local extensions cache path exists
46
- await mkdir(extensionsPath, { recursive: true });
47
- await setSyncStatus(SyncStatus.SYNCING);
48
- logger.trace('Syncing extensions from configured storage location...');
49
- const storage = await getStorage();
50
- const disk = storage.location(env['EXTENSIONS_LOCATION']);
51
- // Make sure we don't overload the file handles
52
- const queue = new Queue({ concurrency: 1000 });
53
- for await (const filepath of disk.list(storageExtensionsPath)) {
54
- const readStream = await disk.read(filepath);
55
- // We want files to be stored in the root of `$TEMP_PATH/extensions`, so gotta remove the
56
- // extensions path on disk from the start of the file path
57
- const destPath = join(extensionsPath, relative(resolve(sep, storageExtensionsPath), resolve(sep, filepath)));
58
- // Ensure that the directory path exists
59
- await mkdir(dirname(destPath), { recursive: true });
60
- const writeStream = createWriteStream(destPath);
61
- queue.add(() => pipeline(readStream, writeStream));
62
- }
63
- await queue.onIdle();
64
- await setSyncStatus(SyncStatus.DONE);
65
- messenger.publish(machineKey, { ready: true });
66
- }
67
- finally {
68
- await lock.delete(machineKey);
69
- }
70
- };
@@ -1,10 +0,0 @@
1
- export declare enum SyncStatus {
2
- UNKNOWN = "UNKNOWN",
3
- SYNCING = "SYNCING",
4
- DONE = "DONE"
5
- }
6
- /**
7
- * Retrieves the sync status from the `.status` file in the local extensions folder
8
- */
9
- export declare const getSyncStatus: () => Promise<string>;
10
- export declare const setSyncStatus: (status: SyncStatus) => Promise<void>;
@@ -1,27 +0,0 @@
1
- import { exists } from 'fs-extra';
2
- import { readFile, writeFile } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { getExtensionsPath } from './get-extensions-path.js';
5
- export var SyncStatus;
6
- (function (SyncStatus) {
7
- SyncStatus["UNKNOWN"] = "UNKNOWN";
8
- SyncStatus["SYNCING"] = "SYNCING";
9
- SyncStatus["DONE"] = "DONE";
10
- })(SyncStatus || (SyncStatus = {}));
11
- /**
12
- * Retrieves the sync status from the `.status` file in the local extensions folder
13
- */
14
- export const getSyncStatus = async () => {
15
- const statusFilePath = join(getExtensionsPath(), '.status');
16
- if (await exists(statusFilePath)) {
17
- const status = await readFile(statusFilePath, 'utf8');
18
- return status;
19
- }
20
- else {
21
- return SyncStatus.UNKNOWN;
22
- }
23
- };
24
- export const setSyncStatus = async (status) => {
25
- const statusFilePath = join(getExtensionsPath(), '.status');
26
- await writeFile(statusFilePath, status);
27
- };
@@ -1,15 +0,0 @@
1
- import type { ToolConfig } from '../types.js';
2
- import { collections } from './collections.js';
3
- import { fields } from './fields.js';
4
- import { files } from './files.js';
5
- import { flows } from './flows.js';
6
- import { items } from './items.js';
7
- import { operations } from './operations.js';
8
- import { relations } from './relations.js';
9
- import { schema } from './schema.js';
10
- import { system } from './system.js';
11
- import { triggerFlow } from './trigger-flow.js';
12
- export declare const ALL_TOOLS: ToolConfig<any>[];
13
- export declare const getAllMcpTools: () => ToolConfig<any>[];
14
- export declare const findMcpTool: (name: string) => ToolConfig<any> | undefined;
15
- export { collections, fields, files, flows, items, operations, relations, schema, system, triggerFlow };
@@ -1,29 +0,0 @@
1
- import { assets } from './assets.js';
2
- import { collections } from './collections.js';
3
- import { fields } from './fields.js';
4
- import { files } from './files.js';
5
- import { flows } from './flows.js';
6
- import { folders } from './folders.js';
7
- import { items } from './items.js';
8
- import { operations } from './operations.js';
9
- import { relations } from './relations.js';
10
- import { schema } from './schema.js';
11
- import { system } from './system.js';
12
- import { triggerFlow } from './trigger-flow.js';
13
- export const ALL_TOOLS = [
14
- system,
15
- items,
16
- files,
17
- folders,
18
- assets,
19
- flows,
20
- triggerFlow,
21
- operations,
22
- schema,
23
- collections,
24
- fields,
25
- relations,
26
- ];
27
- export const getAllMcpTools = () => ALL_TOOLS;
28
- export const findMcpTool = (name) => ALL_TOOLS.find((tool) => tool.name === name);
29
- export { collections, fields, files, flows, items, operations, relations, schema, system, triggerFlow };
@@ -1,16 +0,0 @@
1
- declare const _default: {
2
- assets: string;
3
- collections: string;
4
- fields: string;
5
- files: string;
6
- folders: string;
7
- flows: string;
8
- items: string;
9
- operations: string;
10
- relations: string;
11
- schema: string;
12
- systemPrompt: string;
13
- systemPromptDescription: string;
14
- triggerFlow: string;
15
- };
16
- export default _default;
@@ -1,19 +0,0 @@
1
- import fse from 'fs-extra';
2
- import { dirname, join } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- const __dirname = dirname(fileURLToPath(import.meta.url));
5
- export default {
6
- assets: fse.readFileSync(join(__dirname, 'assets.md'), 'utf8'),
7
- collections: fse.readFileSync(join(__dirname, 'collections.md'), 'utf8'),
8
- fields: fse.readFileSync(join(__dirname, 'fields.md'), 'utf8'),
9
- files: fse.readFileSync(join(__dirname, 'files.md'), 'utf8'),
10
- folders: fse.readFileSync(join(__dirname, 'folders.md'), 'utf8'),
11
- flows: fse.readFileSync(join(__dirname, 'flows.md'), 'utf8'),
12
- items: fse.readFileSync(join(__dirname, 'items.md'), 'utf8'),
13
- operations: fse.readFileSync(join(__dirname, 'operations.md'), 'utf8'),
14
- relations: fse.readFileSync(join(__dirname, 'relations.md'), 'utf8'),
15
- schema: fse.readFileSync(join(__dirname, 'schema.md'), 'utf8'),
16
- systemPrompt: fse.readFileSync(join(__dirname, 'system-prompt.md'), 'utf8'),
17
- systemPromptDescription: fse.readFileSync(join(__dirname, 'system-prompt-description.md'), 'utf8'),
18
- triggerFlow: fse.readFileSync(join(__dirname, 'trigger-flow.md'), 'utf8'),
19
- };
@@ -1,5 +0,0 @@
1
- import type { Accountability } from '@directus/types';
2
- import type { Knex } from 'knex';
3
- import type { GlobalAccess } from '../types.js';
4
- export declare const fetchGlobalAccessForRoles: typeof _fetchGlobalAccessForRoles;
5
- export declare function _fetchGlobalAccessForRoles(accountability: Pick<Accountability, 'roles' | 'ip'>, knex: Knex): Promise<GlobalAccess>;
@@ -1,7 +0,0 @@
1
- import { withCache } from '../../../utils/with-cache.js';
2
- import { fetchGlobalAccessForQuery } from '../utils/fetch-global-access-for-query.js';
3
- export const fetchGlobalAccessForRoles = withCache('global-access-role', _fetchGlobalAccessForRoles, ({ roles, ip }) => ({ roles, ip }));
4
- export async function _fetchGlobalAccessForRoles(accountability, knex) {
5
- const query = knex.where('role', 'in', accountability.roles);
6
- return await fetchGlobalAccessForQuery(query, accountability);
7
- }
@@ -1,5 +0,0 @@
1
- import type { Accountability } from '@directus/types';
2
- import type { Knex } from 'knex';
3
- import type { GlobalAccess } from '../types.js';
4
- export declare const fetchGlobalAccessForUser: typeof _fetchGlobalAccessForUser;
5
- export declare function _fetchGlobalAccessForUser(accountability: Pick<Accountability, 'user' | 'ip'>, knex: Knex): Promise<GlobalAccess>;
@@ -1,10 +0,0 @@
1
- import { withCache } from '../../../utils/with-cache.js';
2
- import { fetchGlobalAccessForQuery } from '../utils/fetch-global-access-for-query.js';
3
- export const fetchGlobalAccessForUser = withCache('global-access-user', _fetchGlobalAccessForUser, ({ user, ip }) => ({
4
- user,
5
- ip,
6
- }));
7
- export async function _fetchGlobalAccessForUser(accountability, knex) {
8
- const query = knex.where('user', '=', accountability.user);
9
- return await fetchGlobalAccessForQuery(query, accountability);
10
- }
@@ -1,4 +0,0 @@
1
- export interface GlobalAccess {
2
- app: boolean;
3
- admin: boolean;
4
- }
@@ -1,4 +0,0 @@
1
- import type { Accountability } from '@directus/types';
2
- import type { Knex } from 'knex';
3
- import type { GlobalAccess } from '../types.js';
4
- export declare function fetchGlobalAccessForQuery(query: Knex.QueryBuilder<any, any[]>, accountability: Pick<Accountability, 'ip'>): Promise<GlobalAccess>;
@@ -1,27 +0,0 @@
1
- import { toBoolean, toArray } from '@directus/utils';
2
- import { ipInNetworks } from '../../../../utils/ip-in-networks.js';
3
- export async function fetchGlobalAccessForQuery(query, accountability) {
4
- const globalAccess = {
5
- app: false,
6
- admin: false,
7
- };
8
- const accessRows = await query
9
- .select('directus_policies.admin_access', 'directus_policies.app_access', 'directus_policies.ip_access')
10
- .from('directus_access')
11
- // @NOTE: `where` clause comes from the caller
12
- .leftJoin('directus_policies', 'directus_policies.id', 'directus_access.policy');
13
- // Additively merge access permissions
14
- for (const { admin_access, app_access, ip_access } of accessRows) {
15
- if (accountability.ip && ip_access) {
16
- // Skip row if IP is not in the allowed networks
17
- const networks = toArray(ip_access);
18
- if (!ipInNetworks(accountability.ip, networks))
19
- continue;
20
- }
21
- globalAccess.admin ||= toBoolean(admin_access);
22
- globalAccess.app ||= globalAccess.admin || toBoolean(app_access);
23
- if (globalAccess.admin)
24
- break;
25
- }
26
- return globalAccess;
27
- }
@@ -1 +0,0 @@
1
- export declare function getDateFormatted(): string;
@@ -1,10 +0,0 @@
1
- export function getDateFormatted() {
2
- const date = new Date();
3
- let month = String(date.getMonth() + 1);
4
- if (month.length === 1)
5
- month = '0' + month;
6
- let day = String(date.getDate());
7
- if (day.length === 1)
8
- day = '0' + day;
9
- return `${date.getFullYear()}${month}${day}-${date.getHours()}${date.getMinutes()}${date.getSeconds()}`;
10
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Checks if an IP address is contained in a list of networks
3
- * @param networks List of IP addresses (192.168.0.1), CIDR notations (192.168.0.0/24) or IP ranges (192-168.0.0-192.168.2.0)
4
- * @throws Will throw if list contains invalid network definitions
5
- */
6
- export declare function ipInNetworks(ip: string, networks: string[]): boolean;
@@ -1,13 +0,0 @@
1
- import { matches } from 'ip-matching';
2
- /**
3
- * Checks if an IP address is contained in a list of networks
4
- * @param networks List of IP addresses (192.168.0.1), CIDR notations (192.168.0.0/24) or IP ranges (192-168.0.0-192.168.2.0)
5
- * @throws Will throw if list contains invalid network definitions
6
- */
7
- export function ipInNetworks(ip, networks) {
8
- for (const allowedIp of networks) {
9
- if (matches(ip, allowedIp))
10
- return true;
11
- }
12
- return false;
13
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes